The java.lang.Double.parseValue
method handles strangely-crafted representations of doubles in an inconsistent way.
If you write a very large number, so large that it is outside of double
's range, but then append a large negative exponent to bring it back in range, you end up in range (illustrated here in Scala's REPL):
scala>
java.lang.Double.parseDouble("10000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000001e-400")
res25: Double = 1.0E-21
On the other hand, if you write a very tiny number, so small that it is outside of double
's range, but then use a large positive exponent to bring it back in range, it only works if the exponent itself is not too large:
scala>
java.lang.Double.parseDouble("0.000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000001e400")
res26: Double = Infinity
scala>
java.lang.Double.parseDouble("0.000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000001e200")
res27: Double = 1.0E-179
Is this simply a bug, or is there a spec somewhere that allows this behavior, or are all of these allowed by spec to fail and one should just thank one's blessings when one gets the correct result? (If it's a bug, has it been fixed?)
(Aside: I was writing custom String-to-double code and was going to defer to the Java default implementation for tricky cases, but this test case failed.)
To check if the string contains numbers only, in the try block, we use Double 's parseDouble() method to convert the string to a Double . If it throws an error (i.e. NumberFormatException error), it means the string isn't a number and numeric is set to false . Else, it's a number.
The parseDouble() method of Java Double class is a built in method in Java that returns a new double initialized to the value represented by the specified String, as done by the valueOf method of class Double. Syntax: public static double parseDouble(String s)
parseDouble() We can parse String to double using parseDouble() method.
Double class is a wrapper class for the primitive type double which contains several methods to effectively deal with a double value like converting it to a string representation, and vice-versa. An object of Double class can hold a single double value.
I think its an edge case, but also a bug. A simpler example is
String text = "0.000000000000000001e326";
System.out.println(Double.parseDouble(text));
System.out.println(new BigDecimal(text).doubleValue());
which prints in Java 7 update 25 and Java 8 update 5
Infinity
1.0E308
The BigDecimal parsing and convert to double shows this number is representable.
It's almost certainly not in the spec. The corresponding section about Floating-Point Literals in the JLS only specifies the values of the floating point literals. But it does not speak about valid representations of them.
Of course, there have to be limits. No one would expect that a string like
String s = "0.00... (3 billion zeros) ...001e3000000000";
to be parsed to 1.0
. But obviously, the limits are much lower here.
This example shows the limit:
public class DoubleTest
{
public static void main(String[] args)
{
runTest(300, 324);
runTest(300, 325);
runTest(300, 326);
}
private static void runTest(int negativeExponent, int exponent)
{
String s = prefix(negativeExponent)+"1e"+exponent+"D";
double d = Double.parseDouble(s);
System.out.println(
"For 1e-"+negativeExponent+" * 1e"+exponent+" result is "+d);
}
private static String prefix(int negativeExponent)
{
StringBuilder sb = new StringBuilder("0.");
for (int i=0; i<negativeExponent; i++)
{
sb.append("0");
}
return sb.toString();
}
}
It prints
For 1e-300 * 1e324 result is 9.999999999999999E22
For 1e-300 * 1e325 result is 1.0E24
For 1e-300 * 1e326 result is Infinity
In fact, it is primarily related to the exponent being used. The relevant part that causes this bailout is in FloatingDecimal.java, line 1996.
It is a bug, but looking at the implementation Oracle might say it's as designed.
The way it's implemented is that the leading kDigits
are converted to a long int. As such, in the first example, the calculated exponent is within the Double
range and it happily returns the result if it falls within the range.
For the second case, it'd figure the exponent is greater than the maximum decimal exponent and return infinity.
For the third case, it'd reach here and returns the expected result.
Although the links above point to source for OpenJDK 6, it's unlikely that they would have touched the source in question for JDK 7 and 8.
Parsing doubles has traditionally been fun. No surprises at the oddities in this case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With