1 /*******************************************************************************
2 * Copyright (c) 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.util;
14 * Internal utility for declaing with hexadecimal double and float literals.
18 public class FloatUtil {
20 private static final int DOUBLE_FRACTION_WIDTH = 52;
22 private static final int DOUBLE_PRECISION = 53;
24 private static final int MAX_DOUBLE_EXPONENT = +1023;
26 private static final int MIN_NORMALIZED_DOUBLE_EXPONENT = -1022;
28 private static final int MIN_UNNORMALIZED_DOUBLE_EXPONENT = MIN_NORMALIZED_DOUBLE_EXPONENT
31 private static final int DOUBLE_EXPONENT_BIAS = +1023;
33 private static final int DOUBLE_EXPONENT_SHIFT = 52;
35 private static final int SINGLE_FRACTION_WIDTH = 23;
37 private static final int SINGLE_PRECISION = 24;
39 private static final int MAX_SINGLE_EXPONENT = +127;
41 private static final int MIN_NORMALIZED_SINGLE_EXPONENT = -126;
43 private static final int MIN_UNNORMALIZED_SINGLE_EXPONENT = MIN_NORMALIZED_SINGLE_EXPONENT
46 private static final int SINGLE_EXPONENT_BIAS = +127;
48 private static final int SINGLE_EXPONENT_SHIFT = 23;
51 * Returns the float value corresponding to the given
52 * hexadecimal floating-point single precision literal.
53 * The literal must be syntactially correct, and must be
54 * a float literal (end in a 'f' or 'F'). It must not
55 * include either leading or trailing whitespace or
58 * This method returns the same answer as
59 * Float.parseFloat(new String(source)) does in JDK 1.5,
60 * except that this method returns Floal.NaN if it
61 * would underflow to 0 (parseFloat just returns 0).
62 * The method handles all the tricky cases, including
63 * fraction rounding to 24 bits and gradual underflow.
66 * @param source source string containing single precision
67 * hexadecimal floating-point literal
68 * @return the float value, including Float.POSITIVE_INFINITY
69 * if the non-zero value is too large to be represented, and
70 * Float.NaN if the non-zero value is too small to be represented
72 public static float valueOfHexFloatLiteral(char[] source) {
73 long bits = convertHexFloatingPointLiteralToBits(source);
74 return Float.intBitsToFloat((int) bits);
78 * Returns the double value corresponding to the given
79 * hexadecimal floating-point double precision literal.
80 * The literal must be syntactially correct, and must be
81 * a double literal (end in an optional 'd' or 'D').
82 * It must not include either leading or trailing whitespace or
85 * This method returns the same answer as
86 * Double.parseDouble(new String(source)) does in JDK 1.5,
87 * except that this method throw NumberFormatException in
88 * the case of overflow to infinity or underflow to 0.
89 * The method handles all the tricky cases, including
90 * fraction rounding to 53 bits and gradual underflow.
93 * @param source source string containing double precision
94 * hexadecimal floating-point literal
95 * @return the double value, including Double.POSITIVE_INFINITY
96 * if the non-zero value is too large to be represented, and
97 * Double.NaN if the non-zero value is too small to be represented
99 public static double valueOfHexDoubleLiteral(char[] source) {
100 long bits = convertHexFloatingPointLiteralToBits(source);
101 return Double.longBitsToDouble(bits);
105 * Returns the given hexadecimal floating-point literal as
106 * the bits for a single-precision (float) or a
107 * double-precision (double) IEEE floating point number.
108 * The literal must be syntactially correct. It must not
109 * include either leading or trailing whitespace or a sign.
111 * @param source source string containing hexadecimal floating-point literal
112 * @return for double precision literals, bits suitable
113 * for passing to Double.longBitsToDouble; for single precision literals,
114 * bits suitable for passing to Single.intBitsToDouble in the bottom
115 * 32 bits of the result
116 * @throws NumberFormatException if the number cannot be parsed
118 private static long convertHexFloatingPointLiteralToBits(char[] source) {
119 int length = source.length;
122 // Step 1: process the '0x' lead-in
124 char nextChar = source[next];
125 nextChar = source[next];
126 if (nextChar == '0') {
129 throw new NumberFormatException();
131 nextChar = source[next];
132 if (nextChar == 'X' || nextChar == 'x') {
135 throw new NumberFormatException();
138 // Step 2: process leading '0's either before or after the '.'
139 int binaryPointPosition = -1;
141 nextChar = source[next];
147 binaryPointPosition = next;
155 // Step 3: process the mantissa
156 // leading zeros have been trimmed
157 int mantissaBits = 0;
158 int leadingDigitPosition = -1;
160 nextChar = source[next];
173 hexdigit = nextChar - '0';
181 hexdigit = (nextChar - 'a') + 10;
189 hexdigit = (nextChar - 'A') + 10;
192 binaryPointPosition = next;
196 if (binaryPointPosition < 0) {
197 // record virtual '.' as being to right of all digits
198 binaryPointPosition = next;
202 if (mantissaBits == 0) {
203 // this is the first non-zero hex digit
204 // ignore leading binary 0's in hex digit
205 leadingDigitPosition = next;
208 } else if (mantissaBits < 60) {
211 mantissa |= hexdigit;
214 // more mantissa bits than we can handle
215 // drop this hex digit on the ground
221 // Step 4: process the 'P'
222 nextChar = source[next];
223 if (nextChar == 'P' || nextChar == 'p') {
226 throw new NumberFormatException();
229 // Step 5: process the exponent
231 int exponentSign = +1;
232 loop: while (next < length) {
233 nextChar = source[next];
253 int digit = nextChar - '0';
254 exponent = (exponent * 10) + digit;
262 // Step 6: process the optional 'f' or 'd'
263 boolean doublePrecision = true;
265 nextChar = source[next];
269 doublePrecision = false;
274 doublePrecision = true;
278 throw new NumberFormatException();
282 // at this point, all the parsing is done
283 // Step 7: handle mantissa of zero
288 // Step 8: normalize non-zero mantissa
289 // mantissa is in right-hand mantissaBits
290 // ensure that top bit (as opposed to hex digit) is 1
291 int scaleFactorCompensation = 0;
292 long top = (mantissa >>> (mantissaBits - 4));
293 if ((top & 0x8) == 0) {
295 scaleFactorCompensation++;
296 if ((top & 0x4) == 0) {
298 scaleFactorCompensation++;
299 if ((top & 0x2) == 0) {
301 scaleFactorCompensation++;
306 // Step 9: convert double literals to IEEE double
308 if (doublePrecision) {
310 if (mantissaBits > DOUBLE_PRECISION) {
311 // more bits than we can keep
312 int extraBits = mantissaBits - DOUBLE_PRECISION;
313 // round to DOUBLE_PRECISION bits
314 fraction = mantissa >>> (extraBits - 1);
315 long lowBit = fraction & 0x1;
317 fraction = fraction >>> 1;
318 if ((fraction & (1L << DOUBLE_PRECISION)) != 0) {
319 fraction = fraction >>> 1;
320 scaleFactorCompensation -= 1;
323 // less bits than the faction can hold - pad on right with 0s
324 fraction = mantissa << (DOUBLE_PRECISION - mantissaBits);
327 int scaleFactor = 0; // how many bits to move '.' to before leading hex digit
328 if (mantissaBits > 0) {
329 if (leadingDigitPosition < binaryPointPosition) {
330 // e.g., 0x80.0p0 has scaleFactor == +8
331 scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition);
332 // e.g., 0x10.0p0 has scaleFactorCompensation == +3
333 scaleFactor -= scaleFactorCompensation;
335 // e.g., 0x0.08p0 has scaleFactor == -4
337 * (leadingDigitPosition - binaryPointPosition - 1);
338 // e.g., 0x0.01p0 has scaleFactorCompensation == +3
339 scaleFactor -= scaleFactorCompensation;
343 int e = (exponentSign * exponent) + scaleFactor;
344 if (e - 1 > MAX_DOUBLE_EXPONENT) {
345 // overflow to +infinity
346 result = Double.doubleToLongBits(Double.POSITIVE_INFINITY);
347 } else if (e - 1 >= MIN_NORMALIZED_DOUBLE_EXPONENT) {
348 // can be represented as a normalized double
349 // the left most bit must be discarded (it's always a 1)
350 long biasedExponent = e - 1 + DOUBLE_EXPONENT_BIAS;
351 result = fraction & ~(1L << DOUBLE_FRACTION_WIDTH);
352 result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT);
353 } else if (e - 1 > MIN_UNNORMALIZED_DOUBLE_EXPONENT) {
354 // can be represented as an unnormalized double
355 long biasedExponent = 0;
356 result = fraction >>> (MIN_NORMALIZED_DOUBLE_EXPONENT - e + 1);
357 result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT);
359 // underflow - return Double.NaN
360 result = Double.doubleToLongBits(Double.NaN);
365 // Step 10: convert float literals to IEEE single
367 if (mantissaBits > SINGLE_PRECISION) {
368 // more bits than we can keep
369 int extraBits = mantissaBits - SINGLE_PRECISION;
370 // round to DOUBLE_PRECISION bits
371 fraction = mantissa >>> (extraBits - 1);
372 long lowBit = fraction & 0x1;
374 fraction = fraction >>> 1;
375 if ((fraction & (1L << SINGLE_PRECISION)) != 0) {
376 fraction = fraction >>> 1;
377 scaleFactorCompensation -= 1;
380 // less bits than the faction can hold - pad on right with 0s
381 fraction = mantissa << (SINGLE_PRECISION - mantissaBits);
384 int scaleFactor = 0; // how many bits to move '.' to before leading hex digit
385 if (mantissaBits > 0) {
386 if (leadingDigitPosition < binaryPointPosition) {
387 // e.g., 0x80.0p0 has scaleFactor == +8
388 scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition);
389 // e.g., 0x10.0p0 has scaleFactorCompensation == +3
390 scaleFactor -= scaleFactorCompensation;
392 // e.g., 0x0.08p0 has scaleFactor == -4
394 * (leadingDigitPosition - binaryPointPosition - 1);
395 // e.g., 0x0.01p0 has scaleFactorCompensation == +3
396 scaleFactor -= scaleFactorCompensation;
400 int e = (exponentSign * exponent) + scaleFactor;
401 if (e - 1 > MAX_SINGLE_EXPONENT) {
402 // overflow to +infinity
403 result = Float.floatToIntBits(Float.POSITIVE_INFINITY);
404 } else if (e - 1 >= MIN_NORMALIZED_SINGLE_EXPONENT) {
405 // can be represented as a normalized single
406 // the left most bit must be discarded (it's always a 1)
407 long biasedExponent = e - 1 + SINGLE_EXPONENT_BIAS;
408 result = fraction & ~(1L << SINGLE_FRACTION_WIDTH);
409 result |= (biasedExponent << SINGLE_EXPONENT_SHIFT);
410 } else if (e - 1 > MIN_UNNORMALIZED_SINGLE_EXPONENT) {
411 // can be represented as an unnormalized single
412 long biasedExponent = 0;
413 result = fraction >>> (MIN_NORMALIZED_SINGLE_EXPONENT - e + 1);
414 result |= (biasedExponent << SINGLE_EXPONENT_SHIFT);
416 // underflow - return Float.NaN
417 result = Float.floatToIntBits(Float.NaN);