1 /*******************************************************************************
2  * Copyright (c) 2004, 2011 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.compiler.util;
15 
16 /**
17  * Internal utility for declaring with hexadecimal double and float literals.
18  *
19  * @since 3.1
20  */
21 public class FloatUtil {
22 
23 	private static final int DOUBLE_FRACTION_WIDTH = 52;
24 
25 	private static final int DOUBLE_PRECISION = 53;
26 
27 	private static final int MAX_DOUBLE_EXPONENT = +1023;
28 
29 	private static final int MIN_NORMALIZED_DOUBLE_EXPONENT = -1022;
30 
31 	private static final int MIN_UNNORMALIZED_DOUBLE_EXPONENT = MIN_NORMALIZED_DOUBLE_EXPONENT
32 			- DOUBLE_PRECISION;
33 
34 	private static final int DOUBLE_EXPONENT_BIAS = +1023;
35 
36 	private static final int DOUBLE_EXPONENT_SHIFT = 52;
37 
38 	private static final int SINGLE_FRACTION_WIDTH = 23;
39 
40 	private static final int SINGLE_PRECISION = 24;
41 
42 	private static final int MAX_SINGLE_EXPONENT = +127;
43 
44 	private static final int MIN_NORMALIZED_SINGLE_EXPONENT = -126;
45 
46 	private static final int MIN_UNNORMALIZED_SINGLE_EXPONENT = MIN_NORMALIZED_SINGLE_EXPONENT
47 			- SINGLE_PRECISION;
48 
49 	private static final int SINGLE_EXPONENT_BIAS = +127;
50 
51 	private static final int SINGLE_EXPONENT_SHIFT = 23;
52 
53 	/**
54 	 * Returns the float value corresponding to the given
55 	 * hexadecimal floating-point single precision literal.
56 	 * The literal must be syntactically correct, and must be
57 	 * a float literal (end in a 'f' or 'F'). It must not
58 	 * include either leading or trailing whitespace or
59 	 * a sign.
60 	 * <p>
61 	 * This method returns the same answer as
62 	 * Float.parseFloat(new String(source)) does in JDK 1.5,
63 	 * except that this method returns Floal.NaN if it
64 	 * would underflow to 0 (parseFloat just returns 0).
65 	 * The method handles all the tricky cases, including
66 	 * fraction rounding to 24 bits and gradual underflow.
67 	 * </p>
68 	 *
69 	 * @param source source string containing single precision
70 	 * hexadecimal floating-point literal
71 	 * @return the float value, including Float.POSITIVE_INFINITY
72 	 * if the non-zero value is too large to be represented, and
73 	 * Float.NaN if the non-zero value is too small to be represented
74 	 */
valueOfHexFloatLiteral(char[] source)75 	public static float valueOfHexFloatLiteral(char[] source) {
76 		long bits = convertHexFloatingPointLiteralToBits(source);
77 		return Float.intBitsToFloat((int) bits);
78 	}
79 
80 	/**
81 	 * Returns the double value corresponding to the given
82 	 * hexadecimal floating-point double precision literal.
83 	 * The literal must be syntactially correct, and must be
84 	 * a double literal (end in an optional 'd' or 'D').
85 	 * It must not include either leading or trailing whitespace or
86 	 * a sign.
87 	 * <p>
88 	 * This method returns the same answer as
89 	 * Double.parseDouble(new String(source)) does in JDK 1.5,
90 	 * except that this method throw NumberFormatException in
91 	 * the case of overflow to infinity or underflow to 0.
92 	 * The method handles all the tricky cases, including
93 	 * fraction rounding to 53 bits and gradual underflow.
94 	 * </p>
95 	 *
96 	 * @param source source string containing double precision
97 	 * hexadecimal floating-point literal
98 	 * @return the double value, including Double.POSITIVE_INFINITY
99 	 * if the non-zero value is too large to be represented, and
100 	 * Double.NaN if the non-zero value is too small to be represented
101 	 */
valueOfHexDoubleLiteral(char[] source)102 	public static double valueOfHexDoubleLiteral(char[] source) {
103 		long bits = convertHexFloatingPointLiteralToBits(source);
104 		return Double.longBitsToDouble(bits);
105 	}
106 
107 	/**
108 	 * Returns the given hexadecimal floating-point literal as
109 	 * the bits for a single-precision  (float) or a
110 	 * double-precision (double) IEEE floating point number.
111 	 * The literal must be syntactically correct.  It must not
112 	 * include either leading or trailing whitespace or a sign.
113 	 *
114 	 * @param source source string containing hexadecimal floating-point literal
115 	 * @return for double precision literals, bits suitable
116 	 * for passing to Double.longBitsToDouble; for single precision literals,
117 	 * bits suitable for passing to Single.intBitsToDouble in the bottom
118 	 * 32 bits of the result
119 	 * @throws NumberFormatException if the number cannot be parsed
120 	 */
convertHexFloatingPointLiteralToBits(char[] source)121 	private static long convertHexFloatingPointLiteralToBits(char[] source) {
122 		int length = source.length;
123 		long mantissa = 0;
124 
125 		// Step 1: process the '0x' lead-in
126 		int next = 0;
127 		char nextChar = source[next];
128 		nextChar = source[next];
129 		if (nextChar == '0') {
130 			next++;
131 		} else {
132 			throw new NumberFormatException();
133 		}
134 		nextChar = source[next];
135 		if (nextChar == 'X' || nextChar == 'x') {
136 			next++;
137 		} else {
138 			throw new NumberFormatException();
139 		}
140 
141 		// Step 2: process leading '0's either before or after the '.'
142 		int binaryPointPosition = -1;
143 		loop: while (true) {
144 			nextChar = source[next];
145 			switch (nextChar) {
146 			case '0':
147 				next++;
148 				continue loop;
149 			case '.':
150 				binaryPointPosition = next;
151 				next++;
152 				continue loop;
153 			default:
154 				break loop;
155 			}
156 		}
157 
158 		// Step 3: process the mantissa
159 		// leading zeros have been trimmed
160 		int mantissaBits = 0;
161 		int leadingDigitPosition = -1;
162 		loop: while (true) {
163 			nextChar = source[next];
164 			int hexdigit;
165 			switch (nextChar) {
166 			case '0':
167 			case '1':
168 			case '2':
169 			case '3':
170 			case '4':
171 			case '5':
172 			case '6':
173 			case '7':
174 			case '8':
175 			case '9':
176 				hexdigit = nextChar - '0';
177 				break;
178 			case 'a':
179 			case 'b':
180 			case 'c':
181 			case 'd':
182 			case 'e':
183 			case 'f':
184 				hexdigit = (nextChar - 'a') + 10;
185 				break;
186 			case 'A':
187 			case 'B':
188 			case 'C':
189 			case 'D':
190 			case 'E':
191 			case 'F':
192 				hexdigit = (nextChar - 'A') + 10;
193 				break;
194 			case '.':
195 				binaryPointPosition = next;
196 				next++;
197 				continue loop;
198 			default:
199 				if (binaryPointPosition < 0) {
200 					// record virtual '.' as being to right of all digits
201 					binaryPointPosition = next;
202 				}
203 				break loop;
204 			}
205 			if (mantissaBits == 0) {
206 				// this is the first non-zero hex digit
207 				// ignore leading binary 0's in hex digit
208 				leadingDigitPosition = next;
209 				mantissa = hexdigit;
210 				mantissaBits = 4;
211 			} else if (mantissaBits < 60) {
212 				// middle hex digits
213 				mantissa <<= 4;
214 				mantissa |= hexdigit;
215 				mantissaBits += 4;
216 			} else {
217 				// more mantissa bits than we can handle
218 				// drop this hex digit on the ground
219 			}
220 			next++;
221 			continue loop;
222 		}
223 
224 		// Step 4: process the 'P'
225 		nextChar = source[next];
226 		if (nextChar == 'P' || nextChar == 'p') {
227 			next++;
228 		} else {
229 			throw new NumberFormatException();
230 		}
231 
232 		// Step 5: process the exponent
233 		int exponent = 0;
234 		int exponentSign = +1;
235 		loop: while (next < length) {
236 			nextChar = source[next];
237 			switch (nextChar) {
238 			case '+':
239 				exponentSign = +1;
240 				next++;
241 				continue loop;
242 			case '-':
243 				exponentSign = -1;
244 				next++;
245 				continue loop;
246 			case '0':
247 			case '1':
248 			case '2':
249 			case '3':
250 			case '4':
251 			case '5':
252 			case '6':
253 			case '7':
254 			case '8':
255 			case '9':
256 				int digit = nextChar - '0';
257 				exponent = (exponent * 10) + digit;
258 				next++;
259 				continue loop;
260 			default:
261 				break loop;
262 			}
263 		}
264 
265 		// Step 6: process the optional 'f' or 'd'
266 		boolean doublePrecision = true;
267 		if (next < length) {
268 			nextChar = source[next];
269 			switch (nextChar) {
270 			case 'f':
271 			case 'F':
272 				doublePrecision = false;
273 				next++;
274 				break;
275 			case 'd':
276 			case 'D':
277 				doublePrecision = true;
278 				next++;
279 				break;
280 			default:
281 				throw new NumberFormatException();
282 			}
283 		}
284 
285 		// at this point, all the parsing is done
286 		// Step 7: handle mantissa of zero
287 		if (mantissa == 0) {
288 			return 0L;
289 		}
290 
291 		// Step 8: normalize non-zero mantissa
292 		// mantissa is in right-hand mantissaBits
293 		// ensure that top bit (as opposed to hex digit) is 1
294 		int scaleFactorCompensation = 0;
295 		long top = (mantissa >>> (mantissaBits - 4));
296 		if ((top & 0x8) == 0) {
297 			mantissaBits--;
298 			scaleFactorCompensation++;
299 			if ((top & 0x4) == 0) {
300 				mantissaBits--;
301 				scaleFactorCompensation++;
302 				if ((top & 0x2) == 0) {
303 					mantissaBits--;
304 					scaleFactorCompensation++;
305 				}
306 			}
307 		}
308 
309 		// Step 9: convert double literals to IEEE double
310 		long result = 0L;
311 		if (doublePrecision) {
312 			long fraction;
313 			if (mantissaBits > DOUBLE_PRECISION) {
314 				// more bits than we can keep
315 				int extraBits = mantissaBits - DOUBLE_PRECISION;
316 				// round to DOUBLE_PRECISION bits
317 				fraction = mantissa >>> (extraBits - 1);
318 				long lowBit = fraction & 0x1;
319 				fraction += lowBit;
320 				fraction = fraction >>> 1;
321 				if ((fraction & (1L << DOUBLE_PRECISION)) != 0) {
322 					fraction = fraction >>> 1;
323 					scaleFactorCompensation -= 1;
324 				}
325 			} else {
326 				// less bits than the faction can hold - pad on right with 0s
327 				fraction = mantissa << (DOUBLE_PRECISION - mantissaBits);
328 			}
329 
330 			int scaleFactor = 0; // how many bits to move '.' to before leading hex digit
331 			if (mantissaBits > 0) {
332 				if (leadingDigitPosition < binaryPointPosition) {
333 					// e.g., 0x80.0p0 has scaleFactor == +8
334 					scaleFactor = 4 * (binaryPointPosition - leadingDigitPosition);
335 					// e.g., 0x10.0p0 has scaleFactorCompensation == +3
336 					scaleFactor -= scaleFactorCompensation;
337 				} else {
338 					// e.g., 0x0.08p0 has scaleFactor == -4
339 					scaleFactor = -4
340 							* (leadingDigitPosition - binaryPointPosition - 1);
341 					// e.g., 0x0.01p0 has scaleFactorCompensation == +3
342 					scaleFactor -= scaleFactorCompensation;
343 				}
344 			}
345 
346 			int e = (exponentSign * exponent) + scaleFactor;
347 			if (e - 1 > MAX_DOUBLE_EXPONENT) {
348 				// overflow to +infinity
349 				result = Double.doubleToLongBits(Double.POSITIVE_INFINITY);
350 			} else if (e - 1 >= MIN_NORMALIZED_DOUBLE_EXPONENT) {
351 				// can be represented as a normalized double
352 				// the left most bit must be discarded (it's always a 1)
353 				long biasedExponent = e - 1 + DOUBLE_EXPONENT_BIAS;
354 				result = fraction & ~(1L << DOUBLE_FRACTION_WIDTH);
355 				result |= (biasedExponent << DOUBLE_EXPONENT_SHIFT);
356 			} else if (e - 1 > MIN_UNNORMALIZED_DOUBLE_EXPONENT) {
357 				// can be represented as an unnormalized double
358 				long biasedExponent = 0;
359 				result = fraction >>> (MIN_NORMALIZED_DOUBLE_EXPONENT - 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 }
425