import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / util / FloatUtil.java
diff --git a/src/org/eclipse/jdt/internal/compiler/util/FloatUtil.java b/src/org/eclipse/jdt/internal/compiler/util/FloatUtil.java
new file mode 100644 (file)
index 0000000..6f2c816
--- /dev/null
@@ -0,0 +1,421 @@
+/*******************************************************************************
+ * 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.jdt.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;
+       }
+}