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