1 /*
   2  * Copyright (c) 2001, 2013, 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         "1.7976931348623158e+308",    // near MAX_VALUE + ulp(MAX_VALUE)/2
 517         "1.7976931348623159e+308",    // near MAX_VALUE + ulp(MAX_VALUE)
 518         
 519         "2.4703282292062329e-324",    // above MIN_VALUE/2
 520         "2.4703282292062327e-324",    // MIN_VALUE/2
 521         "2.4703282292062325e-324",    // below MIN_VALUE/2
 522 
 523         // 1e308 with leading zeros
 524 
 525         "0.0000000000001e321",
 526         "00.000000000000000001e326",
 527         "00000.000000000000000001e326",
 528         "000.0000000000000000001e327",
 529         "0.00000000000000000001e328",
 530     };
 531 
 532     static String paddedBadStrings[];
 533     static String paddedGoodStrings[];
 534     static {
 535         String pad = " \t\n\r\f\u0001\u000b\u001f";
 536         paddedBadStrings = new String[badStrings.length];
 537         for(int i = 0 ; i <  badStrings.length; i++)
 538             paddedBadStrings[i] = pad + badStrings[i] + pad;
 539 
 540         paddedGoodStrings = new String[goodStrings.length];
 541         for(int i = 0 ; i <  goodStrings.length; i++)
 542             paddedGoodStrings[i] = pad + goodStrings[i] + pad;
 543 
 544     }
 545 
 546 
 547     /*
 548      * Throws an exception if <code>Input</code> is
 549      * <code>exceptionalInput</code> and {@link Double.parseDouble
 550      * parseDouble} does <em>not</em> throw an exception or if
 551      * <code>Input</code> is not <code>exceptionalInput</code> and
 552      * <code>parseDouble</code> throws an exception.  This method does
 553      * not attempt to test whether the string is converted to the
 554      * proper value; just whether the input is accepted appropriately
 555      * or not.
 556      */
 557     private static void testParsing(String [] input,
 558                                     boolean exceptionalInput) {
 559         for(int i = 0; i < input.length; i++) {
 560             double d;
 561 
 562             try {
 563                 d = Double.parseDouble(input[i]);
 564                 check(input[i]);
 565             }
 566             catch (NumberFormatException e) {
 567                 if (! exceptionalInput) {
 568                     throw new RuntimeException("Double.parseDouble rejected " +
 569                                                "good string `" + input[i] +
 570                                                "'.");
 571                 }
 572                 break;
 573             }
 574             if (exceptionalInput) {
 575                 throw new RuntimeException("Double.parseDouble accepted " +
 576                                            "bad string `" + input[i] +
 577                                            "'.");
 578             }
 579         }
 580     }
 581 
 582     /*
 583      * Throws an exception if <code>Input</code> is
 584      * <code>exceptionalInput</code> and the regular expression
 585      * matches one of the strings or if <code>Input</code> is not
 586      * <code>exceptionalInput</code> and the regular expression fails
 587      * to match an input string.
 588      */
 589     private static void testRegex(String [] input, boolean exceptionalInput) {
 590         /*
 591          * The regex below is taken from the JavaDoc for
 592          * Double.valueOf.
 593          */
 594 
 595         final String Digits     = "(\\p{Digit}+)";
 596         final String HexDigits  = "(\\p{XDigit}+)";
 597         // an exponent is 'e' or 'E' followed by an optionally
 598         // signed decimal integer.
 599         final String Exp        = "[eE][+-]?"+Digits;
 600         final String fpRegex    =
 601             ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
 602              "[+-]?(" + // Optional sign character
 603              "NaN|" +           // "NaN" string
 604              "Infinity|" +      // "Infinity" string
 605 
 606              // A floating-point string representing a finite positive
 607              // number without a leading sign has at most five basic pieces:
 608              // Digits . Digits ExponentPart FloatTypeSuffix
 609              //
 610              // Since this method allows integer-only strings as input
 611              // in addition to strings of floating-point literals, the
 612              // two sub-patterns below are simplifications of the grammar
 613              // productions from the Java Language Specification, 2nd
 614              // edition, section 3.10.2.
 615 
 616 
 617              // A decimal floating-point string representing a finite positive
 618              // number without a leading sign has at most five basic pieces:
 619              // Digits . Digits ExponentPart FloatTypeSuffix
 620              //
 621              // Since this method allows integer-only strings as input
 622              // in addition to strings of floating-point literals, the
 623              // two sub-patterns below are simplifications of the grammar
 624              // productions from the Java Language Specification, 2nd
 625              // edition, section 3.10.2.
 626 
 627              // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
 628              "(((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
 629 
 630              // . Digits ExponentPart_opt FloatTypeSuffix_opt
 631              "(\\.("+Digits+")("+Exp+")?))|"+
 632 
 633             // Hexadecimal strings
 634             "((" +
 635              // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
 636              "(0[xX]" + HexDigits + "(\\.)?)|" +
 637 
 638              // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
 639              "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
 640 
 641              ")[pP][+-]?" + Digits + "))" +
 642              "[fFdD]?))" +
 643              "[\\x00-\\x20]*");// Optional trailing "whitespace"
 644         Pattern fpPattern = Pattern.compile(fpRegex);
 645 
 646         for(int i = 0; i < input.length; i++) {
 647              Matcher m = fpPattern.matcher(input[i]);
 648              if (m.matches() != ! exceptionalInput) {
 649                  throw new RuntimeException("Regular expression " +
 650                                             (exceptionalInput?
 651                                              "accepted bad":
 652                                              "rejected good") +
 653                                             " string `" +
 654                                             input[i] + "'.");
 655              }
 656         }
 657 
 658     }
 659 
 660     /**
 661      * For each subnormal power of two, test at boundaries of
 662      * region that should convert to that value.
 663      */
 664     private static void testSubnormalPowers() {
 665         boolean failed = false;
 666         BigDecimal TWO = BigDecimal.valueOf(2);
 667         // An ulp is the same for all subnormal values
 668         BigDecimal ulp_BD = new BigDecimal(Double.MIN_VALUE);
 669 
 670         // Test subnormal powers of two (except Double.MIN_VALUE)
 671         for(int i = -1073; i <= -1022; i++) {
 672             double d = Math.scalb(1.0, i);
 673 
 674             /*
 675              * The region [d - ulp/2, d + ulp/2] should round to d.
 676              */
 677             BigDecimal d_BD = new BigDecimal(d);
 678 
 679             BigDecimal lowerBound = d_BD.subtract(ulp_BD.divide(TWO));
 680             BigDecimal upperBound = d_BD.add(ulp_BD.divide(TWO));
 681 
 682             double convertedLowerBound = Double.parseDouble(lowerBound.toString());
 683             double convertedUpperBound = Double.parseDouble(upperBound.toString());
 684             if (convertedLowerBound != d) {
 685                 failed = true;
 686                 System.out.printf("2^%d lowerBound converts as %a %s%n",
 687                                   i, convertedLowerBound, lowerBound);
 688             }
 689             if (convertedUpperBound != d) {
 690                 failed = true;
 691                 System.out.printf("2^%d upperBound converts as %a %s%n",
 692                                   i, convertedUpperBound, upperBound);
 693             }
 694         }
 695         /*
 696          * Double.MIN_VALUE
 697          * The region ]0.5*Double.MIN_VALUE, 1.5*Double.MIN_VALUE[ should round to Double.MIN_VALUE .
 698          */
 699         BigDecimal minValue = new BigDecimal(Double.MIN_VALUE);
 700         if (Double.parseDouble(minValue.multiply(new BigDecimal(0.5)).toString()) != 0.0) {
 701             failed = true;
 702             System.out.printf("0.5*MIN_VALUE doesn't convert 0%n");
 703         }
 704         if (Double.parseDouble(minValue.multiply(new BigDecimal(0.50000000001)).toString()) != Double.MIN_VALUE) {
 705             failed = true;
 706             System.out.printf("0.50000000001*MIN_VALUE doesn't convert to MIN_VALUE%n");
 707         }
 708         if (Double.parseDouble(minValue.multiply(new BigDecimal(1.49999999999)).toString()) != Double.MIN_VALUE) {
 709             failed = true;
 710             System.out.printf("1.49999999999*MIN_VALUE doesn't convert to MIN_VALUE%n");
 711         }
 712         if (Double.parseDouble(minValue.multiply(new BigDecimal(1.5)).toString()) != 2*Double.MIN_VALUE) {
 713             failed = true;
 714             System.out.printf("1.5*MIN_VALUE doesn't convert to 2*MIN_VALUE%n");
 715         }
 716 
 717         if (failed)
 718             throw new RuntimeException("Inconsistent conversion");
 719     }
 720 
 721     /**
 722      * For each power of two, test at boundaries of
 723      * region that should convert to that value.
 724      */
 725     private static void testPowers() {
 726         for(int i = -1074; i <= +1023; i++) {
 727             double d = Math.scalb(1.0, i);
 728             BigDecimal d_BD = new BigDecimal(d);
 729 
 730             BigDecimal lowerBound = d_BD.subtract(new BigDecimal(Math.ulp(Math.nextUp(-d))).multiply(HALF));
 731             BigDecimal upperBound = d_BD.add(new BigDecimal(Math.ulp(d)).multiply(HALF));
 732 
 733             check(lowerBound.toString());
 734             check(upperBound.toString());
 735         }
 736         check(new BigDecimal(Double.MAX_VALUE).add(new BigDecimal(Math.ulp(Double.MAX_VALUE)).multiply(HALF)).toString());
 737     }
 738 
 739     private static void testStrictness() {
 740         final double expected = 0x0.0000008000000p-1022;
 741 //        final double expected = 0x0.0000008000001p-1022;
 742         boolean failed = false;
 743         double conversion = 0.0;
 744         double sum = 0.0; // Prevent conversion from being optimized away
 745 
 746         //2^-1047 + 2^-1075 rounds to 2^-1047
 747         String decimal = "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316";
 748 
 749         for(int i = 0; i <= 12_000; i++) {
 750             conversion = Double.parseDouble(decimal);
 751             sum += conversion;
 752             if (conversion != expected) {
 753                 failed = true;
 754                 System.out.printf("Iteration %d converts as %a%n",
 755                                   i, conversion);
 756             }
 757         }
 758 
 759         System.out.println("Sum = "  + sum);
 760         if (failed)
 761             throw new RuntimeException("Inconsistent conversion");
 762     }
 763 
 764     public static void main(String[] args) throws Exception {
 765         rudimentaryTest();
 766 
 767         testParsing(goodStrings, false);
 768         testParsing(paddedGoodStrings, false);
 769         testParsing(badStrings, true);
 770         testParsing(paddedBadStrings, true);
 771 
 772         testRegex(goodStrings, false);
 773         testRegex(paddedGoodStrings, false);
 774         testRegex(badStrings, true);
 775         testRegex(paddedBadStrings, true);
 776 
 777         testSubnormalPowers();
 778         testPowers();
 779         testStrictness();
 780     }
 781 }