changeset 10701:d245c240f0d7

8043740: Doubles with large exponents overflow to Infinity incorrectly Summary: Modify test of exponent overflow to account for subsequent decrement. Reviewed-by: darcy Contributed-by: Sandipan Razzaque <me@sandipan.net>
author bpb
date Mon, 22 Sep 2014 10:41:45 -0700
parents 71c9aa685da5
children 37d4290391cb
files src/java.base/share/classes/sun/misc/FloatingDecimal.java test/java/lang/Double/ParseDouble.java
diffstat 2 files changed, 41 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/sun/misc/FloatingDecimal.java	Mon Sep 22 10:47:27 2014 +0200
+++ b/src/java.base/share/classes/sun/misc/FloatingDecimal.java	Mon Sep 22 10:41:45 2014 -0700
@@ -1992,21 +1992,32 @@
                         break expLoop; // stop parsing exponent.
                     }
                 }
-                int expLimit = BIG_DECIMAL_EXPONENT+nDigits+nTrailZero;
-                if ( expOverflow || ( expVal > expLimit ) ){
-                    //
-                    // The intent here is to end up with
-                    // infinity or zero, as appropriate.
-                    // The reason for yielding such a small decExponent,
-                    // rather than something intuitive such as
-                    // expSign*Integer.MAX_VALUE, is that this value
-                    // is subject to further manipulation in
-                    // doubleValue() and floatValue(), and I don't want
-                    // it to be able to cause overflow there!
-                    // (The only way we can get into trouble here is for
-                    // really outrageous nDigits+nTrailZero, such as 2 billion. )
-                    //
-                    decExp = expSign*expLimit;
+                int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero;
+                if (expOverflow || (expVal > expLimit)) {
+                    // There is still a chance that the exponent will be safe to
+                    // use: if it would eventually decrease due to a negative
+                    // decExp, and that number is below the limit.  We check for
+                    // that here.
+                    if (!expOverflow && (expSign == 1 && decExp < 0)
+                            && (expVal + decExp) < expLimit) {
+                        // Cannot overflow: adding a positive and negative number.
+                        decExp += expVal;
+                    } else {
+                        //
+                        // The intent here is to end up with
+                        // infinity or zero, as appropriate.
+                        // The reason for yielding such a small decExponent,
+                        // rather than something intuitive such as
+                        // expSign*Integer.MAX_VALUE, is that this value
+                        // is subject to further manipulation in
+                        // doubleValue() and floatValue(), and I don't want
+                        // it to be able to cause overflow there!
+                        // (The only way we can get into trouble here is for
+                        // really outrageous nDigits+nTrailZero, such as 2
+                        // billion.)
+                        //
+                        decExp = expSign * expLimit;
+                    }
                 } else {
                     // this should not overflow, since we tested
                     // for expVal > (MAX+N), where N >= abs(decExp)
--- a/test/java/lang/Double/ParseDouble.java	Mon Sep 22 10:47:27 2014 +0200
+++ b/test/java/lang/Double/ParseDouble.java	Mon Sep 22 10:41:45 2014 -0700
@@ -512,6 +512,21 @@
         "2.2250738585072014e-308",    // Double.MIN_NORMAL
 
         "2.2250738585072012e-308",    // near Double.MIN_NORMAL
+
+        "1.7976931348623158e+308",    // near MAX_VALUE + ulp(MAX_VALUE)/2
+        "1.7976931348623159e+308",    // near MAX_VALUE + ulp(MAX_VALUE)
+
+        "2.4703282292062329e-324",    // above MIN_VALUE/2
+        "2.4703282292062327e-324",    // MIN_VALUE/2
+        "2.4703282292062325e-324",    // below MIN_VALUE/2
+
+        // 1e308 with leading zeros
+
+        "0.0000000000001e321",
+        "00.000000000000000001e326",
+        "00000.000000000000000001e326",
+        "000.0000000000000000001e327",
+        "0.00000000000000000001e328",
     };
 
     static String paddedBadStrings[];