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