JDK-7019078 : Double.parseDouble() converts some subnormal numbers incorrectly
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 6u23
  • Priority: P4
  • Status: Resolved
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2011-02-11
  • Updated: 2013-07-01
  • Resolved: 2013-07-01
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_23"
Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
Java HotSpot(TM) Client VM (build 19.0-b09, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
I am running against a version of Java updated by the FPUpdater tool, although I think my results apply to prior versions.

A DESCRIPTION OF THE PROBLEM :
I ran the testcase found at http://hg.openjdk.java.net/jdk6/jdk6/jdk/rev/d00080320e43. It tries to verify that certain subnormal numbers convert to negative powers of two. It fails; here's the output:

Testing subnormal powers of two.
Exponent -1074, unexpected upper bound converted to 0x0.0000000000002p-1022, not 0x0.0000000000001p-1022.
Exponent -1072, unexpected lower bound converted to 0x0.0000000000003p-1022, not 0x0.0000000000004p-1022.
Exponent -1070, unexpected lower bound converted to 0x0.000000000000fp-1022, not 0x0.000000000001p-1022.
Exponent -1069, unexpected lower bound converted to 0x0.000000000001fp-1022, not 0x0.000000000002p-1022.
Exponent -1068, unexpected lower bound converted to 0x0.000000000003fp-1022, not 0x0.000000000004p-1022.
Exponent -1067, unexpected lower bound converted to 0x0.000000000007fp-1022, not 0x0.000000000008p-1022.
Exponent -1066, unexpected lower bound converted to 0x0.00000000000ffp-1022, not 0x0.00000000001p-1022.
Exponent -1064, unexpected lower bound converted to 0x0.00000000003ffp-1022, not 0x0.00000000004p-1022.
Exponent -1063, unexpected lower bound converted to 0x0.00000000007ffp-1022, not 0x0.00000000008p-1022.
Exponent -1062, unexpected lower bound converted to 0x0.0000000000fffp-1022, not 0x0.0000000001p-1022.
Exponent -1060, unexpected lower bound converted to 0x0.0000000003fffp-1022, not 0x0.0000000004p-1022.
Exponent -1059, unexpected lower bound converted to 0x0.0000000007fffp-1022, not 0x0.0000000008p-1022.
Exponent -1058, unexpected lower bound converted to 0x0.000000000ffffp-1022, not 0x0.000000001p-1022.
Exponent -1057, unexpected lower bound converted to 0x0.000000001ffffp-1022, not 0x0.000000002p-1022.
Exponent -1056, unexpected lower bound converted to 0x0.000000003ffffp-1022, not 0x0.000000004p-1022.
Exponent -1055, unexpected lower bound converted to 0x0.000000007ffffp-1022, not 0x0.000000008p-1022.
Exponent -1054, unexpected lower bound converted to 0x0.00000000fffffp-1022, not 0x0.00000001p-1022.
Exponent -1053, unexpected lower bound converted to 0x0.00000001fffffp-1022, not 0x0.00000002p-1022.
Exponent -1052, unexpected lower bound converted to 0x0.00000003fffffp-1022, not 0x0.00000004p-1022.
Exponent -1051, unexpected lower bound converted to 0x0.00000007fffffp-1022, not 0x0.00000008p-1022.
Exponent -1049, unexpected lower bound converted to 0x0.0000001ffffffp-1022, not 0x0.0000002p-1022.
Exponent -1048, unexpected lower bound converted to 0x0.0000003ffffffp-1022, not 0x0.0000004p-1022.
Exponent -1046, unexpected lower bound converted to 0x0.000000fffffffp-1022, not 0x0.000001p-1022.
Exponent -1044, unexpected lower bound converted to 0x0.000003fffffffp-1022, not 0x0.000004p-1022.
Exponent -1043, unexpected lower bound converted to 0x0.000007fffffffp-1022, not 0x0.000008p-1022.
Exponent -1042, unexpected lower bound converted to 0x0.00000ffffffffp-1022, not 0x0.00001p-1022.
Exponent -1041, unexpected lower bound converted to 0x0.00001ffffffffp-1022, not 0x0.00002p-1022.
Exponent -1040, unexpected lower bound converted to 0x0.00003ffffffffp-1022, not 0x0.00004p-1022.
Exponent -1039, unexpected lower bound converted to 0x0.00007ffffffffp-1022, not 0x0.00008p-1022.
Exponent -1038, unexpected lower bound converted to 0x0.0000fffffffffp-1022, not 0x0.0001p-1022.
Exponent -1037, unexpected lower bound converted to 0x0.0001fffffffffp-1022, not 0x0.0002p-1022.
Exponent -1036, unexpected lower bound converted to 0x0.0003fffffffffp-1022, not 0x0.0004p-1022.
Exponent -1035, unexpected lower bound converted to 0x0.0007fffffffffp-1022, not 0x0.0008p-1022.
Exponent -1034, unexpected lower bound converted to 0x0.000ffffffffffp-1022, not 0x0.001p-1022.
Exponent -1033, unexpected lower bound converted to 0x0.001ffffffffffp-1022, not 0x0.002p-1022.
Exponent -1032, unexpected lower bound converted to 0x0.003ffffffffffp-1022, not 0x0.004p-1022.
Exponent -1031, unexpected lower bound converted to 0x0.007ffffffffffp-1022, not 0x0.008p-1022.
Exponent -1030, unexpected lower bound converted to 0x0.00fffffffffffp-1022, not 0x0.01p-1022.
Exponent -1029, unexpected lower bound converted to 0x0.01fffffffffffp-1022, not 0x0.02p-1022.
Exponent -1028, unexpected lower bound converted to 0x0.03fffffffffffp-1022, not 0x0.04p-1022.
Exponent -1027, unexpected lower bound converted to 0x0.07fffffffffffp-1022, not 0x0.08p-1022.
Exponent -1026, unexpected lower bound converted to 0x0.0ffffffffffffp-1022, not 0x0.1p-1022.
Exponent -1025, unexpected lower bound converted to 0x0.1ffffffffffffp-1022, not 0x0.2p-1022.
Exponent -1024, unexpected lower bound converted to 0x0.3ffffffffffffp-1022, not 0x0.4p-1022.
Exponent -1023, unexpected lower bound converted to 0x0.7ffffffffffffp-1022, not 0x0.8p-1022.
Exponent -1022, unexpected lower bound converted to 0x0.fffffffffffffp-1022, not 0x1.0p-1022.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run testcase below.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Conversions to negative powers of two, as specified in the testcase output, with one exception -- the first line:

Exponent -1074, unexpected upper bound converted to 0x0.0000000000002p-1022, not 0x0.0000000000001p-1022.

This is an error in the testcase, since 2^-1074+2^-1074 = 2^-1073 (in other words, the conversion is right, and the testcase's expectations are wrong).
ACTUAL -
Conversions that are 1 ULP below the correct answer (see testcase output).

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// From http://hg.openjdk.java.net/jdk6/jdk6/jdk/rev/d00080320e43
import java.math.BigDecimal;

class jdk6_testcase {
 /**
 * For each subnormal power of two, test at boundaries of
 * region that should convert to that value.
 */
 private static void testSubnormalPowers() {
 BigDecimal TWO = BigDecimal.valueOf(2);
 // An ulp is the same for all subnormal values
 BigDecimal ulp_BD = new BigDecimal(Double.MIN_VALUE);

 System.out.println("Testing subnormal powers of two.");
 for(int i = -1074; i <= -1022; i++) {
 double d = Math.scalb(1.0, i);

 /*
 * The region [d - ulp/2, d + ulp/2] should round to d.
 */
 BigDecimal d_BD = new BigDecimal(d);

 BigDecimal lowerBound = d_BD.subtract(ulp_BD.divide(TWO));
 BigDecimal upperBound = d_BD.add(ulp_BD.divide(TWO));

 double convertedLowerBound = Double.parseDouble(lowerBound.toString());
 double convertedUpperBound = Double.parseDouble(upperBound.toString());

 if (convertedLowerBound != d) {
 System.out.printf("Exponent %d, unexpected lower bound converted to %a, not %a.%n",
 i, convertedLowerBound, d);
 }

 if (convertedUpperBound != d) {
 System.out.printf("Exponent %d, unexpected upper bound converted to %a, not %a.%n",
 i, convertedUpperBound, d);
 }
 }
 }

 public static void main(String[] args) throws Exception {
   testSubnormalPowers();
 }
} 
---------- END SOURCE ----------

Comments
The test passes since the patch for JDK-7192954 was applied, except for the case of the exponent -1074. For this case the output is Exponent -1074, unexpected lower bound converted to 0x0.0p0, not 0x0.0000000000001p-1022. Exponent -1074, unexpected upper bound converted to 0x0.0000000000002p-1022, not 0x0.0000000000001p-1022. For the case of 2^(-1074), lowerBound is 2^(-1074) - 2^(-1075) = Double.MIN_VALUE/2 which per the IEEE 754 round-to-nearest rule rounds correctly to zero. For this case, upperBound is equivalent to 2^(-1074) + 2^(-1075) which is halfway between 2^(-1074) and 2*2^(-1074). As round-to-nearest mandates that the tie with the least significant bit equal to zero be chosen, the correct outcome after rounding is 2*2^(-1074) which is what is obtained. The test case is therefore incorrect for both lower and upper bounds when the exponent is -1074.
01-07-2013

EVALUATION The original version of the test did demonstrate another long standing issue with parseDouble method. This didn't cause the test to fail but might be confusing when looking at the test output. The test was subsequently updated to remove these messages.
15-02-2011