2011-08-16 71 views
3

我对将此字符串解析为Double时遇到的这种特殊“错误”感到非常困惑。NumberFormat解析问题

我已经设置了NumberFormat属性和符号。

当通过与15个数字和2位小数(例如:str = "333333333333333,33") 一个字符串,并用Number num = NumberFormat.parse(str)解析它的结果是省略了数字。

num的实际值是3.333333333333333E14

这似乎与字符串合作与全1,2的和4的,但...

任何人都可以告诉我吗?

干杯 恩里科

回答

5

DecimalFormat.parse方法,将在这种情况下返回一个Double,其具有有限精度

你不能指望它总是能够返回一个完全代表输入的数字。

您可以使用BigDecimal.setParseBigDecimal来允许数字格式从解析方法中返回BigDecimal。这Number能够以任意精度表示您的值。 (谢谢@Peter Lawrey指出这一点!)

+0

有没有一种解决方法,使它不解析,而是让它变长? – Mallinok

+0

'long'是一个整数类型,因此你会失去小数部分(',33')。 – aioobe

+0

@aioobe,你可以看看Java 1.4的文档吗?这个方法是在Java 5.0中添加的。 http://download.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html#setParseBigDecimal%28boolean%29 –

6

简短的回答;由于圆误差

(double) 111111111111111.11 != (double) 111111111111111.1 

(double) 333333333333333.33 == (double) 333333333333333.3 

如果你想更精确,使用setParseBigDecimal和解析会返回一个BigDecimal。


为什么会发生这种情况?这是因为你处于double精度的极限。这17个很好,因为它可以代表。 2的数量只是双倍,而双店的两个功率是17个中的两个,所以17个和17个八个都是好的。

但是,17三位需要比double多一位来表示该值,并且该最后一位被截断。同样,17五,六和九也有舍入误差。

double[] ds = { 
     111111111111111.11, 
     222222222222222.22, 
     333333333333333.33, 
     444444444444444.44, 
     555555555555555.55, 
     666666666666666.66, 
     777777777777777.77, 
     888888888888888.88, 
     999999999999999.99}; 
for (double d : ds) { 
    System.out.println(d + " - " + new BigDecimal(d)); 
} 

打印以下内容。在打印之前,double稍微圆整,BigDecimal显示双精度值的确切值。

1.1111111111111111E14 - 111111111111111.109375 
2.2222222222222222E14 - 222222222222222.21875 
3.333333333333333E14 - 333333333333333.3125 
4.4444444444444444E14 - 444444444444444.4375 
5.5555555555555556E14 - 555555555555555.5625 
6.666666666666666E14 - 666666666666666.625 
7.777777777777778E14 - 777777777777777.75 
8.888888888888889E14 - 888888888888888.875 
1.0E15 - 1000000000000000 
+1

+1,awsome答案。 – aioobe

+0

@aioobe,来自你,这意味着什么。 ;) –

+0

heh thanks :-)我对你的第二个表达式感到惊讶,所以我写了一个[后续问题](http://stackoverflow.com/questions/7076653/why-is-arbitrary-precision-in-double-literals -allowed-in-java) – aioobe