/******************************************************************************* | |
* Copyright (c) 2004 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Common Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v10.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.wst.jsdt.internal.compiler.util; | |
/** | |
* Internal utility for declaing with hexadecimal double and float literals. | |
* | |
* @since 3.1 | |
*/ | |
public class FloatUtil { | |
private static final int DOUBLE_FRACTION_WIDTH = 52; | |
private static final int DOUBLE_PRECISION = 53; | |
private static final int MAX_DOUBLE_EXPONENT = +1023; | |
private static final int MIN_NORMALIZED_DOUBLE_EXPONENT = -1022; | |
private static final int MIN_UNNORMALIZED_DOUBLE_EXPONENT = MIN_NORMALIZED_DOUBLE_EXPONENT | |
- DOUBLE_PRECISION; | |
private static final int DOUBLE_EXPONENT_BIAS = +1023; | |
private static final int DOUBLE_EXPONENT_SHIFT = 52; | |
private static final int SINGLE_FRACTION_WIDTH = 23; | |
private static final int SINGLE_PRECISION = 24; | |
private static final int MAX_SINGLE_EXPONENT = +127; | |
private static final int MIN_NORMALIZED_SINGLE_EXPONENT = -126; | |
private static final int MIN_UNNORMALIZED_SINGLE_EXPONENT = MIN_NORMALIZED_SINGLE_EXPONENT | |
- SINGLE_PRECISION; | |
private static final int SINGLE_EXPONENT_BIAS = +127; | |
private static final int SINGLE_EXPONENT_SHIFT = 23; | |
/** | |
* Returns the float value corresponding to the given | |
* hexadecimal floating-point single precision literal. | |
* The literal must be syntactially correct, and must be | |
* a float literal (end in a 'f' or 'F'). It must not | |
* include either leading or trailing whitespace or | |
* a sign. | |
* <p> | |
* This method returns the same answer as | |
* Float.parseFloat(new String(source)) does in JDK 1.5, | |
* except that this method returns Floal.NaN if it | |
* would underflow to 0 (parseFloat just returns 0). | |
* The method handles all the tricky cases, including | |
* fraction rounding to 24 bits and gradual underflow. | |
* </p> | |
* | |
* @param source source string containing single precision | |
* hexadecimal floating-point literal | |
* @return the float value, including Float.POSITIVE_INFINITY | |
* if the non-zero value is too large to be represented, and | |
* Float.NaN if the non-zero value is too small to be represented | |
*/ | |
public static float valueOfHexFloatLiteral(char[] source) { | |
long bits = convertHexFloatingPointLiteralToBits(source); | |
return Float.intBitsToFloat((int) bits); | |
} | |
/** | |
* Returns the double value corresponding to the given | |
* hexadecimal floating-point double precision literal. | |
* The literal must be syntactially correct, and must be | |
* a double literal (end in an optional 'd' or 'D'). | |
* It must not include either leading or trailing whitespace or | |
* a sign. | |
* <p> | |
* This method returns the same answer as | |
* Double.parseDouble(new String(source)) does in JDK 1.5, | |
* except that this method throw NumberFormatException in | |
* the case of overflow to infinity or underflow to 0. | |
* The method handles all the tricky cases, including | |
* fraction rounding to 53 bits and gradual underflow. | |
* </p> | |
* | |
* @param source source string containing double precision | |
* hexadecimal floating-point literal | |
* @return the double value, including Double.POSITIVE_INFINITY | |
* if the non-zero value is too large to be represented, and | |
* Double.NaN if the non-zero value is too small to be represented | |
*/ | |
public static double valueOfHexDoubleLiteral(char[] source) { | |
long bits = convertHexFloatingPointLiteralToBits(source); | |
return Double.longBitsToDouble(bits); | |
} | |
/** | |
* Returns the given hexadecimal floating-point literal as | |
* the bits for a single-precision (float) or a | |
* double-precision (double) IEEE floating point number. | |
* The literal must be syntactially correct. It must not | |
* include either leading or trailing whitespace or a sign. | |
* | |
* @param source source string containing hexadecimal floating-point literal | |
* @return for double precision literals, bits suitable | |
* for passing to Double.longBitsToDouble; for single precision literals, | |
* bits suitable for passing to Single.intBitsToDouble in the bottom | |
* 32 bits of the result | |
* @throws NumberFormatException if the number cannot be parsed | |
*/ | |
private static long convertHexFloatingPointLiteralToBits(char[] source) { | |
int length = source.length; | |
long mantissa = 0; | |
// Step 1: process the '0x' lead-in | |
int next = 0; | |
char nextChar = source[next]; | |
nextChar = source[next]; | |
if (nextChar == '0') { | |
next++; | |
} else { | |
throw new NumberFormatException(); | |
} | |
nextChar = source[next]; | |
if (nextChar == 'X' || nextChar == 'x') { | |
next++; | |
} else { | |
throw new NumberFormatException(); | |
} | |
// Step 2: process leading '0's either before or after the '.' | |
int binaryPointPosition = -1; | |
loop: while (true) { | |
nextChar = source[next]; | |
switch (nextChar) { | |
case '0': | |
next++; | |
continue loop; | |
case '.': | |
binaryPointPosition = next; | |
next++; | |
continue loop; | |
default: | |
break loop; | |
} | |
} | |
// Step 3: process the mantissa | |
// leading zeros have been trimmed | |
int mantissaBits = 0; | |
int leadingDigitPosition = -1; | |
loop: while (true) { | |
nextChar = source[next]; | |
int hexdigit; | |
switch (nextChar) { | |
case '0': | |
case '1': | |
case '2': | |
case '3': | |
case '4': | |
case '5': | |
case '6': | |
case '7': | |
case '8': | |
case '9': | |
hexdigit = nextChar - '0'; | |
break; | |
case 'a': | |
case 'b': | |
case 'c': | |
case 'd': | |
case 'e': | |
case 'f': | |
hexdigit = (nextChar - 'a') + 10; | |
break; | |
case 'A': | |
case 'B': | |
case 'C': | |
case 'D': | |
case 'E': | |
case 'F': | |
hexdigit = (nextChar - 'A') + 10; | |
break; | |
case '.': | |
binaryPointPosition = next; | |
next++; | |
continue loop; | |
default: | |
if (binaryPointPosition < 0) { | |
// record virtual '.' as being to right of all digits | |
binaryPointPosition = next; | |
} | |
break loop; | |
} | |
if (mantissaBits == 0) { | |
// this is the first non-zero hex digit | |
// ignore leading binary 0's in hex digit | |
leadingDigitPosition = next; | |
mantissa = hexdigit; | |
mantissaBits = 4; | |
} else if (mantissaBits < 60) { | |
// middle hex digits | |
mantissa <<= 4; | |
mantissa |= hexdigit; | |
mantissaBits += 4; | |
} else { | |
// more mantissa bits than we can handle | |
// drop this hex digit on the ground | |
} | |
next++; | |
continue loop; | |
} | |
// Step 4: process the 'P' | |
nextChar = source[next]; | |
if (nextChar == 'P' || nextChar == 'p') { | |
next++; | |
} else { | |
throw new NumberFormatException(); | |
} | |
// Step 5: process the exponent | |
int exponent = 0; | |
int exponentSign = +1; | |
loop: while (next < length) { | |
nextChar = source[next]; | |
switch (nextChar) { | |
case '+': | |
exponentSign = +1; | |
next++; | |
continue loop; | |
case '-': | |
exponentSign = -1; | |
next++; | |
continue loop; | |
case '0': | |
case '1': | |
case '2': | |
case '3': | |
case '4': | |
case '5': | |
case '6': | |
case '7': | |
case '8': | |
case '9': | |
int digit = nextChar - '0'; | |
exponent = (exponent * 10) + digit; | |
next++; | |
continue loop; | |
default: | |
break loop; | |
} | |
} | |
// Step 6: process the optional 'f' or 'd' | |
boolean doublePrecision = true; | |
if (next < length) { | |
nextChar = source[next]; | |
switch (nextChar) { | |
case 'f': | |
case 'F': | |
doublePrecision = false; | |
next++; | |
break; | |
case 'd': | |
case 'D': | |
doublePrecision = true; | |
next++; | |
break; | |
default: | |
throw new NumberFormatException(); | |
} | |
} | |
// at this point, all the parsing is done | |
// Step 7: handle mantissa of zero | |
if (mantissa == 0) { | |
return 0L; | |
} | |
// Step 8: normalize non-zero mantissa | |
// mantissa is in right-hand mantissaBits | |
// ensure that top bit (as opposed to hex digit) is 1 | |
int scaleFactorCompensation = 0; | |
long top = (mantissa >>> (mantissaBits - 4)); | |
if ((top & 0x8) == 0) { | |
mantissaBits--; | |
scaleFactorCompensation++; | |
if ((top & 0x4) == 0) { | |
mantissaBits--; | |
scaleFactorCompensation++; | |
if ((top & 0x2) == 0) { | |
mantissaBits--; | |
scaleFactorCompensation++; | |
} | |
} | |
} | |
// Step 9: convert double literals to IEEE double | |
long result = 0L; | |
if (doublePrecision) { | |
long fraction; | |
if (mantissaBits > DOUBLE_PRECISION) { | |
// more bits than we can keep | |
int extraBits = mantissaBits - DOUBLE_PRECISION; | |
// round to DOUBLE_PRECISION bits | |
fraction = mantissa >>> (extraBits - 1); | |
long lowBit = fraction & 0x1; | |
fraction += lowBit; | |
fraction = fraction >>> 1; | |
if ((fraction & (1L << DOUBLE_PRECISION)) != 0) { | |
fraction = fraction >>> 1; | |
scaleFactorCompensation -= 1; | |
} | |
} else { | |
// less bits than the faction can hold - pad on right with 0s | |
fraction = mantissa << (DOUBLE_PRECISION - mantissaBits); | |
} | |
int scaleFactor = 0; // how many bits to move '.' to before leading hex digit | |
if (mantissaBits > 0) { | |
if (leadingDigitPosition < binaryPointPosition) { | |
// e.g., 0x80.0p0 has scaleFactor == +8 | |
scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition); | |
// e.g., 0x10.0p0 has scaleFactorCompensation == +3 | |
scaleFactor -= scaleFactorCompensation; | |
} else { | |
// e.g., 0x0.08p0 has scaleFactor == -4 | |
scaleFactor = -4 | |
* (leadingDigitPosition - binaryPointPosition - 1); | |
// e.g., 0x0.01p0 has scaleFactorCompensation == +3 | |
scaleFactor -= scaleFactorCompensation; | |
} | |
} | |
int e = (exponentSign * exponent) + scaleFactor; | |
if (e - 1 > MAX_DOUBLE_EXPONENT) { | |
// overflow to +infinity | |
result = Double.doubleToLongBits(Double.POSITIVE_INFINITY); | |
} else if (e - 1 >= MIN_NORMALIZED_DOUBLE_EXPONENT) { | |
// can be represented as a normalized double | |
// the left most bit must be discarded (it's always a 1) | |
long biasedExponent = e - 1 + DOUBLE_EXPONENT_BIAS; | |
result = fraction & ~(1L << DOUBLE_FRACTION_WIDTH); | |
result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT); | |
} else if (e - 1 > MIN_UNNORMALIZED_DOUBLE_EXPONENT) { | |
// can be represented as an unnormalized double | |
long biasedExponent = 0; | |
result = fraction >>> (MIN_NORMALIZED_DOUBLE_EXPONENT - e + 1); | |
result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT); | |
} else { | |
// underflow - return Double.NaN | |
result = Double.doubleToLongBits(Double.NaN); | |
} | |
return result; | |
} | |
// Step 10: convert float literals to IEEE single | |
long fraction; | |
if (mantissaBits > SINGLE_PRECISION) { | |
// more bits than we can keep | |
int extraBits = mantissaBits - SINGLE_PRECISION; | |
// round to DOUBLE_PRECISION bits | |
fraction = mantissa >>> (extraBits - 1); | |
long lowBit = fraction & 0x1; | |
fraction += lowBit; | |
fraction = fraction >>> 1; | |
if ((fraction & (1L << SINGLE_PRECISION)) != 0) { | |
fraction = fraction >>> 1; | |
scaleFactorCompensation -= 1; | |
} | |
} else { | |
// less bits than the faction can hold - pad on right with 0s | |
fraction = mantissa << (SINGLE_PRECISION - mantissaBits); | |
} | |
int scaleFactor = 0; // how many bits to move '.' to before leading hex digit | |
if (mantissaBits > 0) { | |
if (leadingDigitPosition < binaryPointPosition) { | |
// e.g., 0x80.0p0 has scaleFactor == +8 | |
scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition); | |
// e.g., 0x10.0p0 has scaleFactorCompensation == +3 | |
scaleFactor -= scaleFactorCompensation; | |
} else { | |
// e.g., 0x0.08p0 has scaleFactor == -4 | |
scaleFactor = -4 | |
* (leadingDigitPosition - binaryPointPosition - 1); | |
// e.g., 0x0.01p0 has scaleFactorCompensation == +3 | |
scaleFactor -= scaleFactorCompensation; | |
} | |
} | |
int e = (exponentSign * exponent) + scaleFactor; | |
if (e - 1 > MAX_SINGLE_EXPONENT) { | |
// overflow to +infinity | |
result = Float.floatToIntBits(Float.POSITIVE_INFINITY); | |
} else if (e - 1 >= MIN_NORMALIZED_SINGLE_EXPONENT) { | |
// can be represented as a normalized single | |
// the left most bit must be discarded (it's always a 1) | |
long biasedExponent = e - 1 + SINGLE_EXPONENT_BIAS; | |
result = fraction & ~(1L << SINGLE_FRACTION_WIDTH); | |
result |= (biasedExponent << SINGLE_EXPONENT_SHIFT); | |
} else if (e - 1 > MIN_UNNORMALIZED_SINGLE_EXPONENT) { | |
// can be represented as an unnormalized single | |
long biasedExponent = 0; | |
result = fraction >>> (MIN_NORMALIZED_SINGLE_EXPONENT - e + 1); | |
result |= (biasedExponent << SINGLE_EXPONENT_SHIFT); | |
} else { | |
// underflow - return Float.NaN | |
result = Float.floatToIntBits(Float.NaN); | |
} | |
return result; | |
} | |
} |