Parsing a double from a string which holds a value

2019-04-29 14:52发布

Consider the following java code:

String toParse = "1.7976931348623157E308"; //max value of a double in java        
double parsed = Double.parseDouble(toParse);
System.out.println(parsed);

For the mentioned value of 1.7976931348623157E308 everything makes sense and one gets the correct output.

Now, if one tries to parse 1.7976931348623158E308 (last digit before E incremented) you still get the maximum value printed into the console!
Only after trying to parse 1.7976931348623159E308 (again the last digit got incremented) and greater one gets Infinity.
Same behaviour for the corresponding negative values.

Why is ... 8E308 parsed to ... 7E308 and not Infinity?

1条回答
地球回转人心会变
2楼-- · 2019-04-29 15:44

The SE 7 version of the parseDouble documentation refers to the valueOf documentation which says:

Note that the round-to-nearest rule also implies overflow and underflow behaviour; if the exact value of s is large enough in magnitude (greater than or equal to (MAX_VALUE + ulp(MAX_VALUE)/2), rounding to double will result in an infinity and if the exact value of s is small enough in magnitude (less than or equal to MIN_VALUE/2), rounding to float will result in a zero.

This is consistent with the statement that the rounding to type double is by the usual round-to-nearest rule of IEEE 754 floating-point arithmetic.

You have to imagine the conversion being done by first calculating the nearest floating point number ignoring the exponent limitation, and then checking whether the exponent fits. Double.MAX_VALUE is the closest number under that rule to some numbers that are strictly greater than it.

To confirm this is normal rounding behavior, consider the following program:

    public class Test {
      public static void main(String[] args) {
        double ulp = Math.ulp(Double.MAX_VALUE);
        System.out.println(ulp);
        System.out.println(Double.MAX_VALUE);
        System.out.println(Double.MAX_VALUE+ulp/2.0000000001);
        System.out.println(Double.MAX_VALUE+ulp/2);
      }
    }

It outputs:

1.9958403095347198E292
1.7976931348623157E308
1.7976931348623157E308
Infinity

Adding something even slightly less than half a ulp to Double.MAX_VALUE does not change it. Adding half a ulp overflows to infinity.

查看更多
登录 后发表回答