1 /* 2 * Copyright 2018-2020 Raffaello Giulietti 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 * THE SOFTWARE. 21 */ 22 23 package jdk.internal.math; 24 25 import java.math.BigDecimal; 26 import java.util.Random; 27 28 import static java.lang.Float.*; 29 import static java.lang.Integer.numberOfTrailingZeros; 30 import static java.lang.StrictMath.scalb; 31 import static jdk.internal.math.MathUtils.flog10pow2; 32 33 public class FloatToDecimalChecker extends ToDecimalChecker { 34 35 private static final int P = 36 numberOfTrailingZeros(floatToRawIntBits(3)) + 2; 37 private static final int W = (SIZE - 1) - (P - 1); 38 private static final int Q_MIN = (-1 << W - 1) - P + 3; 39 private static final int Q_MAX = (1 << W - 1) - P; 40 private static final int C_MIN = 1 << P - 1; 41 private static final int C_MAX = (1 << P) - 1; 42 43 private static final int K_MIN = flog10pow2(Q_MIN); 44 private static final int K_MAX = flog10pow2(Q_MAX); 45 private static final int H = flog10pow2(P) + 2; 46 47 private static final float MIN_VALUE = scalb(1.0f, Q_MIN); 48 private static final float MIN_NORMAL = scalb((float) C_MIN, Q_MIN); 49 private static final float MAX_VALUE = scalb((float) C_MAX, Q_MAX); 50 51 private static final int E_MIN = e(MIN_VALUE); 52 private static final int E_MAX = e(MAX_VALUE); 53 54 private static final long C_TINY = cTiny(Q_MIN, K_MIN); 55 56 private float v; 57 private final int originalBits; 58 59 private FloatToDecimalChecker(float v, String s) { 60 super(s); 61 this.v = v; 62 originalBits = floatToRawIntBits(v); 63 } 64 65 @Override 66 BigDecimal toBigDecimal() { 67 return new BigDecimal(v); 68 } 69 70 @Override 71 boolean recovers(BigDecimal b) { 72 return b.floatValue() == v; 73 } 74 75 @Override 76 String hexBits() { 77 return String.format("0x%01X__%02X__%02X_%04X", 78 (originalBits >>> 31) & 0x1, 79 (originalBits >>> 23) & 0xFF, 80 (originalBits >>> 16) & 0x7F, 81 originalBits & 0xFFFF); 82 } 83 84 @Override 85 boolean recovers(String s) { 86 return parseFloat(s) == v; 87 } 88 89 @Override 90 int minExp() { 91 return E_MIN; 92 } 93 94 @Override 95 int maxExp() { 96 return E_MAX; 97 } 98 99 @Override 100 int maxLen10() { 101 return H; 102 } 103 104 @Override 105 boolean isZero() { 106 return v == 0; 107 } 108 109 @Override 110 boolean isInfinity() { 111 return v == POSITIVE_INFINITY; 112 } 113 114 @Override 115 void negate() { 116 v = -v; 117 } 118 119 @Override 120 boolean isNegative() { 121 return originalBits < 0; 122 } 123 124 @Override 125 boolean isNaN() { 126 return Float.isNaN(v); 127 } 128 129 private static void toDec(float v) { 130 // String s = Float.toString(v); 131 String s = FloatToDecimal.toString(v); 132 new FloatToDecimalChecker(v, s).assertTrue(); 133 } 134 135 /* 136 MIN_NORMAL is incorrectly rendered by the JDK. 137 */ 138 private static void testExtremeValues() { 139 toDec(NEGATIVE_INFINITY); 140 toDec(-MAX_VALUE); 141 toDec(-MIN_NORMAL); 142 toDec(-MIN_VALUE); 143 toDec(-0.0f); 144 toDec(0.0f); 145 toDec(MIN_VALUE); 146 toDec(MIN_NORMAL); 147 toDec(MAX_VALUE); 148 toDec(POSITIVE_INFINITY); 149 toDec(NaN); 150 151 /* 152 Quiet NaNs have the most significant bit of the mantissa as 1, 153 while signaling NaNs have it as 0. 154 Exercise 4 combinations of quiet/signaling NaNs and 155 "positive/negative" NaNs. 156 */ 157 toDec(intBitsToFloat(0x7FC0_0001)); 158 toDec(intBitsToFloat(0x7F80_0001)); 159 toDec(intBitsToFloat(0xFFC0_0001)); 160 toDec(intBitsToFloat(0xFF80_0001)); 161 162 /* 163 All values treated specially by Schubfach 164 */ 165 for (int c = 1; c < C_TINY; ++c) { 166 toDec(c * MIN_VALUE); 167 } 168 } 169 170 /* 171 Some "powers of 10" are incorrectly rendered by the JDK. 172 The rendering is either too long or it is not the closest decimal. 173 */ 174 private static void testPowersOf10() { 175 for (int e = E_MIN; e <= E_MAX; ++e) { 176 toDec(parseFloat("1e" + e)); 177 } 178 } 179 180 /* 181 Many powers of 2 are incorrectly rendered by the JDK. 182 The rendering is either too long or it is not the closest decimal. 183 */ 184 private static void testPowersOf2() { 185 for (float v = MIN_VALUE; v <= MAX_VALUE; v *= 2) { 186 toDec(v); 187 } 188 } 189 190 /* 191 There are tons of doubles that are rendered incorrectly by the JDK. 192 While the renderings correctly round back to the original value, 193 they are longer than needed or are not the closest decimal to the double. 194 Here are just a very few examples. 195 */ 196 private static final String[] Anomalies = { 197 // JDK renders these longer than needed. 198 "1.1754944E-38", "2.2E-44", 199 "1.0E16", "2.0E16", "3.0E16", "5.0E16", "3.0E17", 200 "3.2E18", "3.7E18", "3.7E16", "3.72E17", 201 202 // JDK does not render this as the closest. 203 "9.9E-44", 204 }; 205 206 private static void testSomeAnomalies() { 207 for (String dec : Anomalies) { 208 toDec(parseFloat(dec)); 209 } 210 } 211 212 /* 213 Values are from 214 Paxson V, "A Program for Testing IEEE Decimal-Binary Conversion" 215 tables 16 and 17 216 */ 217 private static final float[] PaxsonSignificands = { 218 12_676_506, 219 15_445_013, 220 13_734_123, 221 12_428_269, 222 12_676_506, 223 15_334_037, 224 11_518_287, 225 12_584_953, 226 15_961_084, 227 14_915_817, 228 10_845_484, 229 16_431_059, 230 231 16_093_626, 232 9_983_778, 233 12_745_034, 234 12_706_553, 235 11_005_028, 236 15_059_547, 237 16_015_691, 238 8_667_859, 239 14_855_922, 240 14_855_922, 241 10_144_164, 242 13_248_074, 243 }; 244 245 private static final int[] PaxsonExponents = { 246 -102, 247 -103, 248 86, 249 -138, 250 -130, 251 -146, 252 -41, 253 -145, 254 -125, 255 -146, 256 -102, 257 -61, 258 259 69, 260 25, 261 104, 262 72, 263 45, 264 71, 265 -99, 266 56, 267 -82, 268 -83, 269 -110, 270 95, 271 }; 272 273 private static void testPaxson() { 274 for (int i = 0; i < PaxsonSignificands.length; ++i) { 275 toDec(scalb(PaxsonSignificands[i], PaxsonExponents[i])); 276 } 277 } 278 279 /* 280 Tests all positive integers below 2^23. 281 These are all exact floats and exercise the fast path. 282 */ 283 private static void testInts() { 284 for (int i = 1; i < 1 << P - 1; ++i) { 285 toDec(i); 286 } 287 } 288 289 /* 290 Random floats over the whole range. 291 */ 292 private static void testRandom(int randomCount, Random r) { 293 for (int i = 0; i < randomCount; ++i) { 294 toDec(intBitsToFloat(r.nextInt())); 295 } 296 } 297 298 /* 299 All, really all, 2^32 possible floats. Takes between 90 and 120 minutes. 300 */ 301 public static void testAll() { 302 // Avoid wrapping around Integer.MAX_VALUE 303 int bits = Integer.MIN_VALUE; 304 for (; bits < Integer.MAX_VALUE; ++bits) { 305 toDec(intBitsToFloat(bits)); 306 } 307 toDec(intBitsToFloat(bits)); 308 } 309 310 /* 311 All positive 2^31 floats. 312 */ 313 public static void testPositive() { 314 // Avoid wrapping around Integer.MAX_VALUE 315 int bits = 0; 316 for (; bits < Integer.MAX_VALUE; ++bits) { 317 toDec(intBitsToFloat(bits)); 318 } 319 toDec(intBitsToFloat(bits)); 320 } 321 322 private static void testConstants() { 323 assertTrue(P == FloatToDecimal.P, "P"); 324 assertTrue((long) (float) C_MIN == C_MIN, "C_MIN"); 325 assertTrue((long) (float) C_MAX == C_MAX, "C_MAX"); 326 assertTrue(MIN_VALUE == Float.MIN_VALUE, "MIN_VALUE"); 327 assertTrue(MIN_NORMAL == Float.MIN_NORMAL, "MIN_NORMAL"); 328 assertTrue(MAX_VALUE == Float.MAX_VALUE, "MAX_VALUE"); 329 330 assertTrue(Q_MIN == FloatToDecimal.Q_MIN, "Q_MIN"); 331 assertTrue(Q_MAX == FloatToDecimal.Q_MAX, "Q_MAX"); 332 333 assertTrue(K_MIN == FloatToDecimal.K_MIN, "K_MIN"); 334 assertTrue(K_MAX == FloatToDecimal.K_MAX, "K_MAX"); 335 assertTrue(H == FloatToDecimal.H, "H"); 336 337 assertTrue(E_MIN == FloatToDecimal.E_MIN, "E_MIN"); 338 assertTrue(E_MAX == FloatToDecimal.E_MAX, "E_MAX"); 339 assertTrue(C_TINY == FloatToDecimal.C_TINY, "C_TINY"); 340 } 341 342 public static void test(int randomCount, Random r) { 343 testConstants(); 344 testExtremeValues(); 345 testSomeAnomalies(); 346 testPowersOf2(); 347 testPowersOf10(); 348 testPaxson(); 349 testInts(); 350 testRandom(randomCount, r); 351 } 352 353 public static void main(String[] args) { 354 if (args.length > 0 && args[0].equals("all")) { 355 testAll(); 356 return; 357 } 358 if (args.length > 0 && args[0].equals("positive")) { 359 testPositive(); 360 return; 361 } 362 test(1_000_000, new Random()); 363 } 364 365 }