Rex*_*err 23 java double parsing number-formatting
该java.lang.Double.parseValue方法以不一致的方式处理奇怪的双打表示.
如果你写了一个非常大的数字,那么它超出了double范围,但是然后附加一个大的负指数使它回到范围内,你最终在范围内(这里用Scala的REPL说明):
scala>
java.lang.Double.parseDouble("10000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000001e-400")
res25: Double = 1.0E-21
Run Code Online (Sandbox Code Playgroud)
另一方面,如果你写一个非常小的数字,这么小,它超出了double范围,但是然后使用一个大的正指数将它带回范围内,它只有在指数本身不是太大时才有效:
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
Run Code Online (Sandbox Code Playgroud)
这只是一个错误,或者某个地方是否存在允许这种行为的规范,或者规范允许所有这些都失败了,当得到正确的结果时,应该感谢一个人的祝福?(如果它是一个错误,它已被修复?)
(旁白:我正在编写自定义的字符串到双重代码,并且会针对棘手案例推迟Java默认实现,但此测试用例失败.)
Pet*_*rey 14
我认为它是一个边缘案例,但也是一个错误.一个更简单的例子是
String text = "0.000000000000000001e326";
System.out.println(Double.parseDouble(text));
System.out.println(new BigDecimal(text).doubleValue());
Run Code Online (Sandbox Code Playgroud)
在Java 7 update 25和Java 8 update 5中打印
Infinity
1.0E308
Run Code Online (Sandbox Code Playgroud)
BigDecimal解析并转换为double表示此数字是可表示的.
Mar*_*o13 10
这几乎肯定不符合规范.JLS中有关浮点文字的相应部分仅指定浮点文字的值.但它并没有谈论它们的有效表述.
当然,必须有限制.没有人会想到像这样的字符串
String s = "0.00... (3 billion zeros) ...001e3000000000";
Run Code Online (Sandbox Code Playgroud)
被解析为1.0.但显然,这里的限制要低得多.
此示例显示了限制:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
它打印
对于1e-300*1e324,结果为9.999999999999999E22
对于1e-300*1e325,结果是1.0E24
对于1e-300*1e326,结果是Infinity
实际上,它主要与使用的指数有关.导致这种救助的相关部分是在1996年的FloatingDecimal.java中.