1 /*
   2  * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4160406 4705734 4707389 4826774 4895911 4421494 6358355 7021568 7039369 4396272
  27  * @summary Test for Double.parseDouble method and acceptance regex
  28  */
  29 
  30 import java.math.BigDecimal;
  31 import java.math.BigInteger;
  32 import java.util.regex.*;
  33 
  34 public class ParseDouble {
  35 
  36     private static final BigDecimal HALF = BigDecimal.valueOf(0.5);
  37 
  38     private static void fail(String val, double n) {
  39         throw new RuntimeException("Double.parseDouble failed. String:" +
  40                                                 val + " Result:" + n);
  41     }
  42 
  43     private static void check(String val) {
  44         double n = Double.parseDouble(val);
  45         boolean isNegativeN = n < 0 || n == 0 && 1/n < 0;
  46         double na = Math.abs(n);
  47         String s = val.trim().toLowerCase();
  48         switch (s.charAt(s.length() - 1)) {
  49             case 'd':
  50             case 'f':
  51                 s = s.substring(0, s.length() - 1);
  52                 break;
  53         }
  54         boolean isNegative = false;
  55         if (s.charAt(0) == '+') {
  56             s = s.substring(1);
  57         } else if (s.charAt(0) == '-') {
  58             s = s.substring(1);
  59             isNegative = true;
  60         }
  61         if (s.equals("nan")) {
  62             if (!Double.isNaN(n)) {
  63                 fail(val, n);
  64             }
  65             return;
  66         }
  67         if (Double.isNaN(n)) {
  68             fail(val, n);
  69         }
  70         if (isNegativeN != isNegative)
  71             fail(val, n);
  72         if (s.equals("infinity")) {
  73             if (na != Double.POSITIVE_INFINITY) {
  74                 fail(val, n);
  75             }
  76             return;
  77         }
  78         BigDecimal bd;
  79         if (s.startsWith("0x")) {
  80             s = s.substring(2);
  81             int indP = s.indexOf('p');
  82             long exp = Long.parseLong(s.substring(indP + 1));
  83             int indD = s.indexOf('.');
  84             String significand;
  85             if (indD >= 0) {
  86                 significand = s.substring(0, indD) + s.substring(indD + 1, indP);
  87                 exp -= 4*(indP - indD - 1);
  88             } else {
  89                 significand = s.substring(0, indP);
  90             }
  91             bd = new BigDecimal(new BigInteger(significand, 16));
  92             if (exp >= 0) {
  93                 bd = bd.multiply(BigDecimal.valueOf(2).pow((int)exp));
  94             } else {
  95                 bd = bd.divide(BigDecimal.valueOf(2).pow((int)-exp));
  96             }
  97         } else {
  98             bd = new BigDecimal(s);
  99         }
 100         BigDecimal l, u;
 101         if (Double.isInfinite(na)) {
 102             l = new BigDecimal(Double.MAX_VALUE).add(new BigDecimal(Math.ulp(Double.MAX_VALUE)).multiply(HALF));
 103             u = null;
 104         } else {
 105             l = new BigDecimal(na).subtract(new BigDecimal(Math.ulp(Math.nextUp(-na))).multiply(HALF));
 106             u = new BigDecimal(na).add(new BigDecimal(Math.ulp(n)).multiply(HALF));
 107         }
 108         int cmpL = bd.compareTo(l);
 109         int cmpU = u != null ? bd.compareTo(u) : -1;
 110         if ((Double.doubleToLongBits(n) & 1) != 0) {
 111             if (cmpL <= 0 || cmpU >= 0) {
 112                 fail(val, n);
 113             }
 114         } else {
 115             if (cmpL < 0 || cmpU > 0) {
 116                 fail(val, n);
 117             }
 118         }
 119     }
 120 
 121     private static void check(String val, double expected) {
 122         double n = Double.parseDouble(val);
 123         if (n != expected)
 124             fail(val, n);
 125         check(val);
 126     }
 127 
 128     private static void rudimentaryTest() {
 129         check(new String(""+Double.MIN_VALUE), Double.MIN_VALUE);
 130         check(new String(""+Double.MAX_VALUE), Double.MAX_VALUE);
 131 
 132         check("10",     (double)  10.0);
 133         check("10.0",   (double)  10.0);
 134         check("10.01",  (double)  10.01);
 135 
 136         check("-10",    (double) -10.0);
 137         check("-10.00", (double) -10.0);
 138         check("-10.01", (double) -10.01);
 139     }
 140 
 141 
 142     static  String badStrings[] = {
 143         "",
 144         "+",
 145         "-",
 146         "+e",
 147         "-e",
 148         "+e170",
 149         "-e170",
 150 
 151         // Make sure intermediate white space is not deleted.
 152         "1234   e10",
 153         "-1234   e10",
 154 
 155         // Control characters in the interior of a string are not legal
 156         "1\u0007e1",
 157         "1e\u00071",
 158 
 159         // NaN and infinity can't have trailing type suffices or exponents
 160         "NaNf",
 161         "NaNF",
 162         "NaNd",
 163         "NaND",
 164         "-NaNf",
 165         "-NaNF",
 166         "-NaNd",
 167         "-NaND",
 168         "+NaNf",
 169         "+NaNF",
 170         "+NaNd",
 171         "+NaND",
 172         "Infinityf",
 173         "InfinityF",
 174         "Infinityd",
 175         "InfinityD",
 176         "-Infinityf",
 177         "-InfinityF",
 178         "-Infinityd",
 179         "-InfinityD",
 180         "+Infinityf",
 181         "+InfinityF",
 182         "+Infinityd",
 183         "+InfinityD",
 184 
 185         "NaNe10",
 186         "-NaNe10",
 187         "+NaNe10",
 188         "Infinitye10",
 189         "-Infinitye10",
 190         "+Infinitye10",
 191 
 192         // Non-ASCII digits are not recognized
 193         "\u0661e\u0661", // 1e1 in Arabic-Indic digits
 194         "\u06F1e\u06F1", // 1e1 in Extended Arabic-Indic digits
 195         "\u0967e\u0967", // 1e1 in Devanagari digits
 196 
 197         // JCK test lex03592m3
 198         ".",
 199 
 200         // JCK test lex03592m4
 201         "e42",
 202 
 203         // JCK test lex03592m5
 204         ".e42",
 205 
 206         // JCK test lex03592m6
 207         "d",
 208 
 209         // JCK test lex03592m7
 210         ".d",
 211 
 212         // JCK test lex03592m8
 213         "e42d",
 214 
 215         // JCK test lex03592m9
 216         ".e42d",
 217 
 218         // JCK test lex03593m10
 219         "1A01.01125e-10d",
 220 
 221         // JCK test lex03593m11
 222         "2;3.01125e-10d",
 223 
 224         // JCK test lex03593m12
 225         "1_34.01125e-10d",
 226 
 227         // JCK test lex03593m14
 228         "202..01125e-10d",
 229 
 230         // JCK test lex03593m15
 231         "202,01125e-10d",
 232 
 233         // JCK test lex03593m16
 234         "202.03b4e-10d",
 235 
 236         // JCK test lex03593m18
 237         "202.06_3e-10d",
 238 
 239         // JCK test lex03593m20
 240         "202.01125e-f0d",
 241 
 242         // JCK test lex03593m21
 243         "202.01125e_3d",
 244 
 245         // JCK test lex03593m22
 246         "202.01125e -5d",
 247 
 248         // JCK test lex03593m24
 249         "202.01125e-10r",
 250 
 251         // JCK test lex03593m25
 252         "202.01125e-10ff",
 253 
 254         // JCK test lex03593m26
 255         "1234L.01",
 256 
 257         // JCK test lex03593m27
 258         "12ee-2",
 259 
 260         // JCK test lex03593m28
 261         "12e-2.2.2",
 262 
 263         // JCK test lex03593m29
 264         "12.01e+",
 265 
 266         // JCK test lex03593m30
 267         "12.01E",
 268 
 269         // Bad hexadecimal-style strings
 270 
 271         // Two leading zeros
 272         "00x1.0p1",
 273 
 274         // Must have hex specifier
 275         "1.0p1",
 276         "00010p1",
 277         "deadbeefp1",
 278 
 279         // Need an explicit fully-formed exponent
 280         "0x1.0p",
 281         "0x1.0",
 282 
 283         // Exponent must be in decimal
 284         "0x1.0pa",
 285         "0x1.0pf",
 286 
 287         // Exponent separated by "p"
 288         "0x1.0e22",
 289         "0x1.0e22",
 290 
 291         // Need a signifcand
 292         "0xp22"
 293     };
 294 
 295     static String goodStrings[] = {
 296         "NaN",
 297         "+NaN",
 298         "-NaN",
 299         "Infinity",
 300         "+Infinity",
 301         "-Infinity",
 302         "1.1e-23f",
 303         ".1e-23f",
 304         "1e-23",
 305         "1f",
 306         "0",
 307         "-0",
 308         "+0",
 309         "00",
 310         "00",
 311         "-00",
 312         "+00",
 313         "0000000000",
 314         "-0000000000",
 315         "+0000000000",
 316         "1",
 317         "2",
 318         "1234",
 319         "-1234",
 320         "+1234",
 321         "2147483647",   // Integer.MAX_VALUE
 322         "2147483648",
 323         "-2147483648",  // Integer.MIN_VALUE
 324         "-2147483649",
 325 
 326         "16777215",
 327         "16777216",     // 2^24
 328         "16777217",
 329 
 330         "-16777215",
 331         "-16777216",    // -2^24
 332         "-16777217",
 333 
 334         "9007199254740991",
 335         "9007199254740992",     // 2^53
 336         "9007199254740993",
 337 
 338         "-9007199254740991",
 339         "-9007199254740992",    // -2^53
 340         "-9007199254740993",
 341 
 342         "9223372036854775807",
 343         "9223372036854775808",  // Long.MAX_VALUE
 344         "9223372036854775809",
 345 
 346         "-9223372036854775808",
 347         "-9223372036854775809", // Long.MIN_VALUE
 348         "-9223372036854775810",
 349 
 350         // Culled from JCK test lex03591m1
 351         "54.07140d",
 352         "7.01e-324d",
 353         "2147483647.01d",
 354         "1.2147483647f",
 355         "000000000000000000000000001.F",
 356         "1.00000000000000000000000000e-2F",
 357 
 358         // Culled from JCK test lex03592m2
 359         "2.",
 360         ".0909",
 361         "122112217090.0",
 362         "7090e-5",
 363         "2.E-20",
 364         ".0909e42",
 365         "122112217090.0E+100",
 366         "7090f",
 367         "2.F",
 368         ".0909d",
 369         "122112217090.0D",
 370         "7090e-5f",
 371         "2.E-20F",
 372         ".0909e42d",
 373         "122112217090.0E+100D",
 374 
 375         // Culled from JCK test lex03594m31 -- unicode escapes
 376         "\u0035\u0031\u0034\u0039\u0032\u0033\u0036\u0037\u0038\u0030.1102E-209D",
 377         "1290873\u002E12301e100",
 378         "1.1E-10\u0066",
 379 
 380         // Culled from JCK test lex03595m1
 381         "0.0E-10",
 382         "1E10",
 383 
 384         // Culled from JCK test lex03691m1
 385         "0.f",
 386         "1f",
 387         "0.F",
 388         "1F",
 389         "0.12d",
 390         "1e-0d",
 391         "12.e+1D",
 392         "0e-0D",
 393         "12.e+01",
 394         "1e-01",
 395 
 396         // Good hex strings
 397         // Vary capitalization of separators.
 398 
 399         "0x1p1",
 400         "0X1p1",
 401         "0x1P1",
 402         "0X1P1",
 403         "0x1p1f",
 404         "0X1p1f",
 405         "0x1P1f",
 406         "0X1P1f",
 407         "0x1p1F",
 408         "0X1p1F",
 409         "0x1P1F",
 410         "0X1P1F",
 411         "0x1p1d",
 412         "0X1p1d",
 413         "0x1P1d",
 414         "0X1P1d",
 415         "0x1p1D",
 416         "0X1p1D",
 417         "0x1P1D",
 418         "0X1P1D",
 419 
 420         "-0x1p1",
 421         "-0X1p1",
 422         "-0x1P1",
 423         "-0X1P1",
 424         "-0x1p1f",
 425         "-0X1p1f",
 426         "-0x1P1f",
 427         "-0X1P1f",
 428         "-0x1p1F",
 429         "-0X1p1F",
 430         "-0x1P1F",
 431         "-0X1P1F",
 432         "-0x1p1d",
 433         "-0X1p1d",
 434         "-0x1P1d",
 435         "-0X1P1d",
 436         "-0x1p1D",
 437         "-0X1p1D",
 438         "-0x1P1D",
 439         "-0X1P1D",
 440 
 441         "0x1p-1",
 442         "0X1p-1",
 443         "0x1P-1",
 444         "0X1P-1",
 445         "0x1p-1f",
 446         "0X1p-1f",
 447         "0x1P-1f",
 448         "0X1P-1f",
 449         "0x1p-1F",
 450         "0X1p-1F",
 451         "0x1P-1F",
 452         "0X1P-1F",
 453         "0x1p-1d",
 454         "0X1p-1d",
 455         "0x1P-1d",
 456         "0X1P-1d",
 457         "0x1p-1D",
 458         "0X1p-1D",
 459         "0x1P-1D",
 460         "0X1P-1D",
 461 
 462         "-0x1p-1",
 463         "-0X1p-1",
 464         "-0x1P-1",
 465         "-0X1P-1",
 466         "-0x1p-1f",
 467         "-0X1p-1f",
 468         "-0x1P-1f",
 469         "-0X1P-1f",
 470         "-0x1p-1F",
 471         "-0X1p-1F",
 472         "-0x1P-1F",
 473         "-0X1P-1F",
 474         "-0x1p-1d",
 475         "-0X1p-1d",
 476         "-0x1P-1d",
 477         "-0X1P-1d",
 478         "-0x1p-1D",
 479         "-0X1p-1D",
 480         "-0x1P-1D",
 481         "-0X1P-1D",
 482 
 483 
 484         // Try different significand combinations
 485         "0xap1",
 486         "0xbp1",
 487         "0xcp1",
 488         "0xdp1",
 489         "0xep1",
 490         "0xfp1",
 491 
 492         "0x1p1",
 493         "0x.1p1",
 494         "0x1.1p1",
 495 
 496         "0x001p23",
 497         "0x00.1p1",
 498         "0x001.1p1",
 499 
 500         "0x100p1",
 501         "0x.100p1",
 502         "0x1.100p1",
 503 
 504         "0x00100p1",
 505         "0x00.100p1",
 506         "0x001.100p1",
 507 
 508         // Limits
 509 
 510         "1.7976931348623157E308",     // Double.MAX_VALUE
 511         "4.9e-324",                   // Double.MIN_VALUE
 512         "2.2250738585072014e-308",    // Double.MIN_NORMAL
 513 
 514         "2.2250738585072012e-308",    // near Double.MIN_NORMAL
 515     };
 516 
 517     static String paddedBadStrings[];
 518     static String paddedGoodStrings[];
 519     static {
 520         String pad = " \t\n\r\f\u0001\u000b\u001f";
 521         paddedBadStrings = new String[badStrings.length];
 522         for(int i = 0 ; i <  badStrings.length; i++)
 523             paddedBadStrings[i] = pad + badStrings[i] + pad;
 524 
 525         paddedGoodStrings = new String[goodStrings.length];
 526         for(int i = 0 ; i <  goodStrings.length; i++)
 527             paddedGoodStrings[i] = pad + goodStrings[i] + pad;
 528 
 529     }
 530 
 531 
 532     /*
 533      * Throws an exception if <code>Input</code> is
 534      * <code>exceptionalInput</code> and {@link Double.parseDouble
 535      * parseDouble} does <em>not</em> throw an exception or if
 536      * <code>Input</code> is not <code>exceptionalInput</code> and
 537      * <code>parseDouble</code> throws an exception.  This method does
 538      * not attempt to test whether the string is converted to the
 539      * proper value; just whether the input is accepted appropriately
 540      * or not.
 541      */
 542     private static void testParsing(String [] input,
 543                                     boolean exceptionalInput) {
 544         for(int i = 0; i < input.length; i++) {
 545             double d;
 546 
 547             try {
 548                 d = Double.parseDouble(input[i]);
 549                 check(input[i]);
 550             }
 551             catch (NumberFormatException e) {
 552                 if (! exceptionalInput) {
 553                     throw new RuntimeException("Double.parseDouble rejected " +
 554                                                "good string `" + input[i] +
 555                                                "'.");
 556                 }
 557                 break;
 558             }
 559             if (exceptionalInput) {
 560                 throw new RuntimeException("Double.parseDouble accepted " +
 561                                            "bad string `" + input[i] +
 562                                            "'.");
 563             }
 564         }
 565     }
 566 
 567     /*
 568      * Throws an exception if <code>Input</code> is
 569      * <code>exceptionalInput</code> and the regular expression
 570      * matches one of the strings or if <code>Input</code> is not
 571      * <code>exceptionalInput</code> and the regular expression fails
 572      * to match an input string.
 573      */
 574     private static void testRegex(String [] input, boolean exceptionalInput) {
 575         /*
 576          * The regex below is taken from the JavaDoc for
 577          * Double.valueOf.
 578          */
 579 
 580         final String Digits     = "(\\p{Digit}+)";
 581         final String HexDigits  = "(\\p{XDigit}+)";
 582         // an exponent is 'e' or 'E' followed by an optionally
 583         // signed decimal integer.
 584         final String Exp        = "[eE][+-]?"+Digits;
 585         final String fpRegex    =
 586             ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
 587              "[+-]?(" + // Optional sign character
 588              "NaN|" +           // "NaN" string
 589              "Infinity|" +      // "Infinity" string
 590 
 591              // A floating-point string representing a finite positive
 592              // number without a leading sign has at most five basic pieces:
 593              // Digits . Digits ExponentPart FloatTypeSuffix
 594              //
 595              // Since this method allows integer-only strings as input
 596              // in addition to strings of floating-point literals, the
 597              // two sub-patterns below are simplifications of the grammar
 598              // productions from the Java Language Specification, 2nd
 599              // edition, section 3.10.2.
 600 
 601 
 602              // A decimal floating-point string representing a finite positive
 603              // number without a leading sign has at most five basic pieces:
 604              // Digits . Digits ExponentPart FloatTypeSuffix
 605              //
 606              // Since this method allows integer-only strings as input
 607              // in addition to strings of floating-point literals, the
 608              // two sub-patterns below are simplifications of the grammar
 609              // productions from the Java Language Specification, 2nd
 610              // edition, section 3.10.2.
 611 
 612              // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
 613              "(((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
 614 
 615              // . Digits ExponentPart_opt FloatTypeSuffix_opt
 616              "(\\.("+Digits+")("+Exp+")?))|"+
 617 
 618             // Hexadecimal strings
 619             "((" +
 620              // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
 621              "(0[xX]" + HexDigits + "(\\.)?)|" +
 622 
 623              // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
 624              "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
 625 
 626              ")[pP][+-]?" + Digits + "))" +
 627              "[fFdD]?))" +
 628              "[\\x00-\\x20]*");// Optional trailing "whitespace"
 629         Pattern fpPattern = Pattern.compile(fpRegex);
 630 
 631         for(int i = 0; i < input.length; i++) {
 632              Matcher m = fpPattern.matcher(input[i]);
 633              if (m.matches() != ! exceptionalInput) {
 634                  throw new RuntimeException("Regular expression " +
 635                                             (exceptionalInput?
 636                                              "accepted bad":
 637                                              "rejected good") +
 638                                             " string `" +
 639                                             input[i] + "'.");
 640              }
 641         }
 642 
 643     }
 644 
 645     /**
 646      * For each subnormal power of two, test at boundaries of
 647      * region that should convert to that value.
 648      */
 649     private static void testSubnormalPowers() {
 650         boolean failed = false;
 651         BigDecimal TWO = BigDecimal.valueOf(2);
 652         // An ulp is the same for all subnormal values
 653         BigDecimal ulp_BD = new BigDecimal(Double.MIN_VALUE);
 654 
 655         // Test subnormal powers of two (except Double.MIN_VALUE)
 656         for(int i = -1073; i <= -1022; i++) {
 657             double d = Math.scalb(1.0, i);
 658 
 659             /*
 660              * The region [d - ulp/2, d + ulp/2] should round to d.
 661              */
 662             BigDecimal d_BD = new BigDecimal(d);
 663 
 664             BigDecimal lowerBound = d_BD.subtract(ulp_BD.divide(TWO));
 665             BigDecimal upperBound = d_BD.add(ulp_BD.divide(TWO));
 666 
 667             double convertedLowerBound = Double.parseDouble(lowerBound.toString());
 668             double convertedUpperBound = Double.parseDouble(upperBound.toString());
 669             if (convertedLowerBound != d) {
 670                 failed = true;
 671                 System.out.printf("2^%d lowerBound converts as %a %s%n",
 672                                   i, convertedLowerBound, lowerBound);
 673             }
 674             if (convertedUpperBound != d) {
 675                 failed = true;
 676                 System.out.printf("2^%d upperBound converts as %a %s%n",
 677                                   i, convertedUpperBound, upperBound);
 678             }
 679         }
 680         /*
 681          * Double.MIN_VALUE
 682          * The region ]0.5*Double.MIN_VALUE, 1.5*Double.MIN_VALUE[ should round to Double.MIN_VALUE .
 683          */
 684         BigDecimal minValue = new BigDecimal(Double.MIN_VALUE);
 685         if (Double.parseDouble(minValue.multiply(new BigDecimal(0.5)).toString()) != 0.0) {
 686             failed = true;
 687             System.out.printf("0.5*MIN_VALUE doesn't convert 0%n");
 688         }
 689         if (Double.parseDouble(minValue.multiply(new BigDecimal(0.50000000001)).toString()) != Double.MIN_VALUE) {
 690             failed = true;
 691             System.out.printf("0.50000000001*MIN_VALUE doesn't convert to MIN_VALUE%n");
 692         }
 693         if (Double.parseDouble(minValue.multiply(new BigDecimal(1.49999999999)).toString()) != Double.MIN_VALUE) {
 694             failed = true;
 695             System.out.printf("1.49999999999*MIN_VALUE doesn't convert to MIN_VALUE%n");
 696         }
 697         if (Double.parseDouble(minValue.multiply(new BigDecimal(1.5)).toString()) != 2*Double.MIN_VALUE) {
 698             failed = true;
 699             System.out.printf("1.5*MIN_VALUE doesn't convert to 2*MIN_VALUE%n");
 700         }
 701 
 702         if (failed)
 703             throw new RuntimeException("Inconsistent conversion");
 704     }
 705 
 706     /**
 707      * For each power of two, test at boundaries of
 708      * region that should convert to that value.
 709      */
 710     private static void testPowers() {
 711         for(int i = -1074; i <= +1023; i++) {
 712             double d = Math.scalb(1.0, i);
 713             BigDecimal d_BD = new BigDecimal(d);
 714 
 715             BigDecimal lowerBound = d_BD.subtract(new BigDecimal(Math.ulp(Math.nextUp(-d))).multiply(HALF));
 716             BigDecimal upperBound = d_BD.add(new BigDecimal(Math.ulp(d)).multiply(HALF));
 717 
 718             check(lowerBound.toString());
 719             check(upperBound.toString());
 720         }
 721         check(new BigDecimal(Double.MAX_VALUE).add(new BigDecimal(Math.ulp(Double.MAX_VALUE)).multiply(HALF)).toString());
 722     }
 723 
 724     private static void testStrictness() {
 725         final double expected = 0x0.0000008000000p-1022;
 726 //        final double expected = 0x0.0000008000001p-1022;
 727         boolean failed = false;
 728         double conversion = 0.0;
 729         double sum = 0.0; // Prevent conversion from being optimized away
 730 
 731         //2^-1047 + 2^-1075 rounds to 2^-1047
 732         String decimal = "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316";
 733 
 734         for(int i = 0; i <= 12_000; i++) {
 735             conversion = Double.parseDouble(decimal);
 736             sum += conversion;
 737             if (conversion != expected) {
 738                 failed = true;
 739                 System.out.printf("Iteration %d converts as %a%n",
 740                                   i, conversion);
 741             }
 742         }
 743 
 744         System.out.println("Sum = "  + sum);
 745         if (failed)
 746             throw new RuntimeException("Inconsistent conversion");
 747     }
 748 
 749     public static void main(String[] args) throws Exception {
 750         rudimentaryTest();
 751 
 752         testParsing(goodStrings, false);
 753         testParsing(paddedGoodStrings, false);
 754         testParsing(badStrings, true);
 755         testParsing(paddedBadStrings, true);
 756 
 757         testRegex(goodStrings, false);
 758         testRegex(paddedGoodStrings, false);
 759         testRegex(badStrings, true);
 760         testRegex(paddedBadStrings, true);
 761 
 762         testSubnormalPowers();
 763         testPowers();
 764         testStrictness();
 765     }
 766 }