001: /*******************************************************************************
002: * Copyright (c) 2004, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.util;
011:
012: /**
013: * Internal utility for declaing with hexadecimal double and float literals.
014: *
015: * @since 3.1
016: */
017: public class FloatUtil {
018:
019: private static final int DOUBLE_FRACTION_WIDTH = 52;
020:
021: private static final int DOUBLE_PRECISION = 53;
022:
023: private static final int MAX_DOUBLE_EXPONENT = +1023;
024:
025: private static final int MIN_NORMALIZED_DOUBLE_EXPONENT = -1022;
026:
027: private static final int MIN_UNNORMALIZED_DOUBLE_EXPONENT = MIN_NORMALIZED_DOUBLE_EXPONENT
028: - DOUBLE_PRECISION;
029:
030: private static final int DOUBLE_EXPONENT_BIAS = +1023;
031:
032: private static final int DOUBLE_EXPONENT_SHIFT = 52;
033:
034: private static final int SINGLE_FRACTION_WIDTH = 23;
035:
036: private static final int SINGLE_PRECISION = 24;
037:
038: private static final int MAX_SINGLE_EXPONENT = +127;
039:
040: private static final int MIN_NORMALIZED_SINGLE_EXPONENT = -126;
041:
042: private static final int MIN_UNNORMALIZED_SINGLE_EXPONENT = MIN_NORMALIZED_SINGLE_EXPONENT
043: - SINGLE_PRECISION;
044:
045: private static final int SINGLE_EXPONENT_BIAS = +127;
046:
047: private static final int SINGLE_EXPONENT_SHIFT = 23;
048:
049: /**
050: * Returns the float value corresponding to the given
051: * hexadecimal floating-point single precision literal.
052: * The literal must be syntactially correct, and must be
053: * a float literal (end in a 'f' or 'F'). It must not
054: * include either leading or trailing whitespace or
055: * a sign.
056: * <p>
057: * This method returns the same answer as
058: * Float.parseFloat(new String(source)) does in JDK 1.5,
059: * except that this method returns Floal.NaN if it
060: * would underflow to 0 (parseFloat just returns 0).
061: * The method handles all the tricky cases, including
062: * fraction rounding to 24 bits and gradual underflow.
063: * </p>
064: *
065: * @param source source string containing single precision
066: * hexadecimal floating-point literal
067: * @return the float value, including Float.POSITIVE_INFINITY
068: * if the non-zero value is too large to be represented, and
069: * Float.NaN if the non-zero value is too small to be represented
070: */
071: public static float valueOfHexFloatLiteral(char[] source) {
072: long bits = convertHexFloatingPointLiteralToBits(source);
073: return Float.intBitsToFloat((int) bits);
074: }
075:
076: /**
077: * Returns the double value corresponding to the given
078: * hexadecimal floating-point double precision literal.
079: * The literal must be syntactially correct, and must be
080: * a double literal (end in an optional 'd' or 'D').
081: * It must not include either leading or trailing whitespace or
082: * a sign.
083: * <p>
084: * This method returns the same answer as
085: * Double.parseDouble(new String(source)) does in JDK 1.5,
086: * except that this method throw NumberFormatException in
087: * the case of overflow to infinity or underflow to 0.
088: * The method handles all the tricky cases, including
089: * fraction rounding to 53 bits and gradual underflow.
090: * </p>
091: *
092: * @param source source string containing double precision
093: * hexadecimal floating-point literal
094: * @return the double value, including Double.POSITIVE_INFINITY
095: * if the non-zero value is too large to be represented, and
096: * Double.NaN if the non-zero value is too small to be represented
097: */
098: public static double valueOfHexDoubleLiteral(char[] source) {
099: long bits = convertHexFloatingPointLiteralToBits(source);
100: return Double.longBitsToDouble(bits);
101: }
102:
103: /**
104: * Returns the given hexadecimal floating-point literal as
105: * the bits for a single-precision (float) or a
106: * double-precision (double) IEEE floating point number.
107: * The literal must be syntactially correct. It must not
108: * include either leading or trailing whitespace or a sign.
109: *
110: * @param source source string containing hexadecimal floating-point literal
111: * @return for double precision literals, bits suitable
112: * for passing to Double.longBitsToDouble; for single precision literals,
113: * bits suitable for passing to Single.intBitsToDouble in the bottom
114: * 32 bits of the result
115: * @throws NumberFormatException if the number cannot be parsed
116: */
117: private static long convertHexFloatingPointLiteralToBits(
118: char[] source) {
119: int length = source.length;
120: long mantissa = 0;
121:
122: // Step 1: process the '0x' lead-in
123: int next = 0;
124: char nextChar = source[next];
125: nextChar = source[next];
126: if (nextChar == '0') {
127: next++;
128: } else {
129: throw new NumberFormatException();
130: }
131: nextChar = source[next];
132: if (nextChar == 'X' || nextChar == 'x') {
133: next++;
134: } else {
135: throw new NumberFormatException();
136: }
137:
138: // Step 2: process leading '0's either before or after the '.'
139: int binaryPointPosition = -1;
140: loop: while (true) {
141: nextChar = source[next];
142: switch (nextChar) {
143: case '0':
144: next++;
145: continue loop;
146: case '.':
147: binaryPointPosition = next;
148: next++;
149: continue loop;
150: default:
151: break loop;
152: }
153: }
154:
155: // Step 3: process the mantissa
156: // leading zeros have been trimmed
157: int mantissaBits = 0;
158: int leadingDigitPosition = -1;
159: loop: while (true) {
160: nextChar = source[next];
161: int hexdigit;
162: switch (nextChar) {
163: case '0':
164: case '1':
165: case '2':
166: case '3':
167: case '4':
168: case '5':
169: case '6':
170: case '7':
171: case '8':
172: case '9':
173: hexdigit = nextChar - '0';
174: break;
175: case 'a':
176: case 'b':
177: case 'c':
178: case 'd':
179: case 'e':
180: case 'f':
181: hexdigit = (nextChar - 'a') + 10;
182: break;
183: case 'A':
184: case 'B':
185: case 'C':
186: case 'D':
187: case 'E':
188: case 'F':
189: hexdigit = (nextChar - 'A') + 10;
190: break;
191: case '.':
192: binaryPointPosition = next;
193: next++;
194: continue loop;
195: default:
196: if (binaryPointPosition < 0) {
197: // record virtual '.' as being to right of all digits
198: binaryPointPosition = next;
199: }
200: break loop;
201: }
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;
206: mantissa = hexdigit;
207: mantissaBits = 4;
208: } else if (mantissaBits < 60) {
209: // middle hex digits
210: mantissa <<= 4;
211: mantissa |= hexdigit;
212: mantissaBits += 4;
213: } else {
214: // more mantissa bits than we can handle
215: // drop this hex digit on the ground
216: }
217: next++;
218: continue loop;
219: }
220:
221: // Step 4: process the 'P'
222: nextChar = source[next];
223: if (nextChar == 'P' || nextChar == 'p') {
224: next++;
225: } else {
226: throw new NumberFormatException();
227: }
228:
229: // Step 5: process the exponent
230: int exponent = 0;
231: int exponentSign = +1;
232: loop: while (next < length) {
233: nextChar = source[next];
234: switch (nextChar) {
235: case '+':
236: exponentSign = +1;
237: next++;
238: continue loop;
239: case '-':
240: exponentSign = -1;
241: next++;
242: continue loop;
243: case '0':
244: case '1':
245: case '2':
246: case '3':
247: case '4':
248: case '5':
249: case '6':
250: case '7':
251: case '8':
252: case '9':
253: int digit = nextChar - '0';
254: exponent = (exponent * 10) + digit;
255: next++;
256: continue loop;
257: default:
258: break loop;
259: }
260: }
261:
262: // Step 6: process the optional 'f' or 'd'
263: boolean doublePrecision = true;
264: if (next < length) {
265: nextChar = source[next];
266: switch (nextChar) {
267: case 'f':
268: case 'F':
269: doublePrecision = false;
270: next++;
271: break;
272: case 'd':
273: case 'D':
274: doublePrecision = true;
275: next++;
276: break;
277: default:
278: throw new NumberFormatException();
279: }
280: }
281:
282: // at this point, all the parsing is done
283: // Step 7: handle mantissa of zero
284: if (mantissa == 0) {
285: return 0L;
286: }
287:
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) {
294: mantissaBits--;
295: scaleFactorCompensation++;
296: if ((top & 0x4) == 0) {
297: mantissaBits--;
298: scaleFactorCompensation++;
299: if ((top & 0x2) == 0) {
300: mantissaBits--;
301: scaleFactorCompensation++;
302: }
303: }
304: }
305:
306: // Step 9: convert double literals to IEEE double
307: long result = 0L;
308: if (doublePrecision) {
309: long fraction;
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;
316: fraction += lowBit;
317: fraction = fraction >>> 1;
318: if ((fraction & (1L << DOUBLE_PRECISION)) != 0) {
319: fraction = fraction >>> 1;
320: scaleFactorCompensation -= 1;
321: }
322: } else {
323: // less bits than the faction can hold - pad on right with 0s
324: fraction = mantissa << (DOUBLE_PRECISION - mantissaBits);
325: }
326:
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;
334: } else {
335: // e.g., 0x0.08p0 has scaleFactor == -4
336: scaleFactor = -4
337: * (leadingDigitPosition
338: - binaryPointPosition - 1);
339: // e.g., 0x0.01p0 has scaleFactorCompensation == +3
340: scaleFactor -= scaleFactorCompensation;
341: }
342: }
343:
344: int e = (exponentSign * exponent) + scaleFactor;
345: if (e - 1 > MAX_DOUBLE_EXPONENT) {
346: // overflow to +infinity
347: result = Double
348: .doubleToLongBits(Double.POSITIVE_INFINITY);
349: } else if (e - 1 >= MIN_NORMALIZED_DOUBLE_EXPONENT) {
350: // can be represented as a normalized double
351: // the left most bit must be discarded (it's always a 1)
352: long biasedExponent = e - 1 + DOUBLE_EXPONENT_BIAS;
353: result = fraction & ~(1L << DOUBLE_FRACTION_WIDTH);
354: result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT);
355: } else if (e - 1 > MIN_UNNORMALIZED_DOUBLE_EXPONENT) {
356: // can be represented as an unnormalized double
357: long biasedExponent = 0;
358: result = fraction >>> (MIN_NORMALIZED_DOUBLE_EXPONENT
359: - e + 1);
360: result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT);
361: } else {
362: // underflow - return Double.NaN
363: result = Double.doubleToLongBits(Double.NaN);
364: }
365: return result;
366: }
367:
368: // Step 10: convert float literals to IEEE single
369: long fraction;
370: if (mantissaBits > SINGLE_PRECISION) {
371: // more bits than we can keep
372: int extraBits = mantissaBits - SINGLE_PRECISION;
373: // round to DOUBLE_PRECISION bits
374: fraction = mantissa >>> (extraBits - 1);
375: long lowBit = fraction & 0x1;
376: fraction += lowBit;
377: fraction = fraction >>> 1;
378: if ((fraction & (1L << SINGLE_PRECISION)) != 0) {
379: fraction = fraction >>> 1;
380: scaleFactorCompensation -= 1;
381: }
382: } else {
383: // less bits than the faction can hold - pad on right with 0s
384: fraction = mantissa << (SINGLE_PRECISION - mantissaBits);
385: }
386:
387: int scaleFactor = 0; // how many bits to move '.' to before leading hex digit
388: if (mantissaBits > 0) {
389: if (leadingDigitPosition < binaryPointPosition) {
390: // e.g., 0x80.0p0 has scaleFactor == +8
391: scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition);
392: // e.g., 0x10.0p0 has scaleFactorCompensation == +3
393: scaleFactor -= scaleFactorCompensation;
394: } else {
395: // e.g., 0x0.08p0 has scaleFactor == -4
396: scaleFactor = -4
397: * (leadingDigitPosition - binaryPointPosition - 1);
398: // e.g., 0x0.01p0 has scaleFactorCompensation == +3
399: scaleFactor -= scaleFactorCompensation;
400: }
401: }
402:
403: int e = (exponentSign * exponent) + scaleFactor;
404: if (e - 1 > MAX_SINGLE_EXPONENT) {
405: // overflow to +infinity
406: result = Float.floatToIntBits(Float.POSITIVE_INFINITY);
407: } else if (e - 1 >= MIN_NORMALIZED_SINGLE_EXPONENT) {
408: // can be represented as a normalized single
409: // the left most bit must be discarded (it's always a 1)
410: long biasedExponent = e - 1 + SINGLE_EXPONENT_BIAS;
411: result = fraction & ~(1L << SINGLE_FRACTION_WIDTH);
412: result |= (biasedExponent << SINGLE_EXPONENT_SHIFT);
413: } else if (e - 1 > MIN_UNNORMALIZED_SINGLE_EXPONENT) {
414: // can be represented as an unnormalized single
415: long biasedExponent = 0;
416: result = fraction >>> (MIN_NORMALIZED_SINGLE_EXPONENT - e + 1);
417: result |= (biasedExponent << SINGLE_EXPONENT_SHIFT);
418: } else {
419: // underflow - return Float.NaN
420: result = Float.floatToIntBits(Float.NaN);
421: }
422: return result;
423: }
424: }
|