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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.util;
12 
13 /**
14  * Internal utility for declaing with hexadecimal double and float literals.
15  *
16  * @since 3.1
17  */
18 public class FloatUtil {
19 
20 	private static final int DOUBLE_FRACTION_WIDTH = 52;
21 
22 	private static final int DOUBLE_PRECISION = 53;
23 
24 	private static final int MAX_DOUBLE_EXPONENT = +1023;
25 
26 	private static final int MIN_NORMALIZED_DOUBLE_EXPONENT = -1022;
27 
28 	private static final int MIN_UNNORMALIZED_DOUBLE_EXPONENT = MIN_NORMALIZED_DOUBLE_EXPONENT
29 			- DOUBLE_PRECISION;
30 
31 	private static final int DOUBLE_EXPONENT_BIAS = +1023;
32 
33 	private static final int DOUBLE_EXPONENT_SHIFT = 52;
34 
35 	private static final int SINGLE_FRACTION_WIDTH = 23;
36 
37 	private static final int SINGLE_PRECISION = 24;
38 
39 	private static final int MAX_SINGLE_EXPONENT = +127;
40 
41 	private static final int MIN_NORMALIZED_SINGLE_EXPONENT = -126;
42 
43 	private static final int MIN_UNNORMALIZED_SINGLE_EXPONENT = MIN_NORMALIZED_SINGLE_EXPONENT
44 			- SINGLE_PRECISION;
45 
46 	private static final int SINGLE_EXPONENT_BIAS = +127;
47 
48 	private static final int SINGLE_EXPONENT_SHIFT = 23;
49 
50 	/**
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
56 	 * a sign.
57 	 * <p>
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.
64 	 * </p>
65 	 *
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
71 	 */
valueOfHexFloatLiteral(char[] source)72 	public static float valueOfHexFloatLiteral(char[] source) {
73 		long bits = convertHexFloatingPointLiteralToBits(source);
74 		return Float.intBitsToFloat((int) bits);
75 	}
76 
77 	/**
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
83 	 * a sign.
84 	 * <p>
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.
91 	 * </p>
92 	 *
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
98 	 */
valueOfHexDoubleLiteral(char[] source)99 	public static double valueOfHexDoubleLiteral(char[] source) {
100 		long bits = convertHexFloatingPointLiteralToBits(source);
101 		return Double.longBitsToDouble(bits);
102 	}
103 
104 	/**
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.
110 	 *
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
117 	 */
convertHexFloatingPointLiteralToBits(char[] source)118 	private static long convertHexFloatingPointLiteralToBits(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 - binaryPointPosition - 1);
338 					// e.g., 0x0.01p0 has scaleFactorCompensation == +3
339 					scaleFactor -= scaleFactorCompensation;
340 				}
341 			}
342 
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);
358 			} else {
359 				// underflow - return Double.NaN
360 				result = Double.doubleToLongBits(Double.NaN);
361 			}
362 			return result;
363 		}
364 
365 		// Step 10: convert float literals to IEEE single
366 		long fraction;
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;
373 			fraction += lowBit;
374 			fraction = fraction >>> 1;
375 			if ((fraction & (1L << SINGLE_PRECISION)) != 0) {
376 				fraction = fraction >>> 1;
377 				scaleFactorCompensation -= 1;
378 			}
379 		} else {
380 			// less bits than the faction can hold - pad on right with 0s
381 			fraction = mantissa << (SINGLE_PRECISION - mantissaBits);
382 		}
383 
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;
391 			} else {
392 				// e.g., 0x0.08p0 has scaleFactor == -4
393 				scaleFactor = -4
394 						* (leadingDigitPosition - binaryPointPosition - 1);
395 				// e.g., 0x0.01p0 has scaleFactorCompensation == +3
396 				scaleFactor -= scaleFactorCompensation;
397 			}
398 		}
399 
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);
415 		} else {
416 			// underflow - return Float.NaN
417 			result = Float.floatToIntBits(Float.NaN);
418 		}
419 		return result;
420 	}
421 }
422