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 7021568 7039369
27 * @summary Test for Double.parseDouble method and acceptance regex
28 */
29
30 import java.util.regex.*;
31 import java.math.BigDecimal;
32
33 public class ParseDouble {
34
35 private static void check(String val, double expected) {
36 double n = Double.parseDouble(val);
37 if (n != expected)
38 throw new RuntimeException("Double.parseDouble failed. String:" +
39 val + " Result:" + n);
40 }
41
42 private static void rudimentaryTest() {
43 check(new String(""+Double.MIN_VALUE), Double.MIN_VALUE);
44 check(new String(""+Double.MAX_VALUE), Double.MAX_VALUE);
45
46 check("10", (double) 10.0);
47 check("10.0", (double) 10.0);
48 check("10.01", (double) 10.01);
49
50 check("-10", (double) -10.0);
51 check("-10.00", (double) -10.0);
52 check("-10.01", (double) -10.01);
53 }
54
55
56 static String badStrings[] = {
57 "",
58 "+",
59 "-",
443 }
444
445
446 /*
447 * Throws an exception if <code>Input</code> is
448 * <code>exceptionalInput</code> and {@link Double.parseDouble
449 * parseDouble} does <em>not</em> throw an exception or if
450 * <code>Input</code> is not <code>exceptionalInput</code> and
451 * <code>parseDouble</code> throws an exception. This method does
452 * not attempt to test whether the string is converted to the
453 * proper value; just whether the input is accepted appropriately
454 * or not.
455 */
456 private static void testParsing(String [] input,
457 boolean exceptionalInput) {
458 for(int i = 0; i < input.length; i++) {
459 double d;
460
461 try {
462 d = Double.parseDouble(input[i]);
463 }
464 catch (NumberFormatException e) {
465 if (! exceptionalInput) {
466 throw new RuntimeException("Double.parseDouble rejected " +
467 "good string `" + input[i] +
468 "'.");
469 }
470 break;
471 }
472 if (exceptionalInput) {
473 throw new RuntimeException("Double.parseDouble accepted " +
474 "bad string `" + input[i] +
475 "'.");
476 }
477 }
478 }
479
480 /*
481 * Throws an exception if <code>Input</code> is
482 * <code>exceptionalInput</code> and the regular expression
543
544 for(int i = 0; i < input.length; i++) {
545 Matcher m = fpPattern.matcher(input[i]);
546 if (m.matches() != ! exceptionalInput) {
547 throw new RuntimeException("Regular expression " +
548 (exceptionalInput?
549 "accepted bad":
550 "rejected good") +
551 " string `" +
552 input[i] + "'.");
553 }
554 }
555
556 }
557
558 /**
559 * For each subnormal power of two, test at boundaries of
560 * region that should convert to that value.
561 */
562 private static void testSubnormalPowers() {
563 BigDecimal TWO = BigDecimal.valueOf(2);
564 // An ulp is the same for all subnormal values
565 BigDecimal ulp_BD = new BigDecimal(Double.MIN_VALUE);
566
567 // Test subnormal powers of two
568 for(int i = -1074; i <= -1022; i++) {
569 double d = Math.scalb(1.0, i);
570
571 /*
572 * The region [d - ulp/2, d + ulp/2] should round to d.
573 */
574 BigDecimal d_BD = new BigDecimal(d);
575
576 BigDecimal lowerBound = d_BD.subtract(ulp_BD.divide(TWO));
577 BigDecimal upperBound = d_BD.add(ulp_BD.divide(TWO));
578
579 double convertedLowerBound = Double.parseDouble(lowerBound.toString());
580 double convertedUpperBound = Double.parseDouble(upperBound.toString());
581 }
582 }
583
584
585 private static void testStrictness() {
586 final double expected = 0x0.0000008000001p-1022;
587 boolean failed = false;
588 double conversion = 0.0;
589 double sum = 0.0; // Prevent conversion from being optimized away
590
591 //2^-1047 + 2^-1075
592 String decimal = "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316";
593
594 for(int i = 0; i <= 12_000; i++) {
595 conversion = Double.parseDouble(decimal);
596 sum += conversion;
597 if (conversion != expected) {
598 failed = true;
599 System.out.printf("Iteration %d converts as %a%n",
600 i, conversion);
601 }
602 }
603
604 System.out.println("Sum = " + sum);
605 if (failed)
606 throw new RuntimeException("Inconsistent conversion");
607 }
608
609 public static void main(String[] args) throws Exception {
610 rudimentaryTest();
611
612 testParsing(goodStrings, false);
613 testParsing(paddedGoodStrings, false);
614 testParsing(badStrings, true);
615 testParsing(paddedBadStrings, true);
616
617 testRegex(goodStrings, false);
618 testRegex(paddedGoodStrings, false);
619 testRegex(badStrings, true);
620 testRegex(paddedBadStrings, true);
621
622 testSubnormalPowers();
623 testStrictness();
624 }
625 }
|
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 "-",
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
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 }
|