2014-02-25 33 views
4

我试图使用DecimalFormat来格式化双数,只打印2位小数的数字(如果它有小数部分),否则我想按原样打印数字。当数字很小时,下面的代码可以正常工作,但数字很大,但它不能按预期工作。使用DecimalFormat格式化大的双数

DecimalFormat df = new DecimalFormat("#.##"); //have tried just # too 
    double d1 = 56789d; 
    System.out.println(df.format(d1)); //works fine - prints 56789 

    double d2 = 1234567879123456789d; 
    System.out.println(df.format(d2)); // does not work 

第二输出1234567879123456770,而我想1234567879123456789。对于带小数部分的双精度值,我只想保留两位小数点。

有什么问题的建议吗?

+0

我怀疑你是'double''s(im)precision的受害者... – fge

回答

7

关于为什么解析值关闭19的说明在于如何表示double值,因为IEEE floating-point numbers具有53位精度。也就是说,对于输入的大数值,精度实际上大于1。方法Math.ulp,对于“最后一个单位”,给出最接近的double值可以在其论点的大小上分开。

double d2 = 1234567879123456789d; 
DecimalFormat df = new DecimalFormat("#.##"); 
System.out.println(Math.ulp(d2)); 
System.out.println(df.format(d2)); 

此输出

256.0 
1234567879123456770 

所以,你得到的最接近double价值给你在源代码中键入数字。 Section 3.10.2 of the JLS覆盖double文字:

的类型float元素,并且是可以使用IEEE 754的32位单精度和64位双精度二进制浮点格式来表示这些值,分别双。

对于浮点类的方法valueOf和包java.lang的类Double,描述了从浮点数的Unicode字符串表示形式到内部IEEE 754二进制浮点表示形式的正确输入转换的详细信息。

并且参照Double.valueOf javadocs

s的视为代表在常用的“计算机科学记数法”或者是一个精确的十六进制值的精确十进制值;然后将该确切的数值概念转换为“无限精确”的二进制值,然后通过IEEE 754浮点运算的通常的舍入到最近的规则舍入为double类型[012]

此外,该值仍在long值的范围内,该值仍将正确表示整数值。

long l2 = 1234567879123456789L; 
DecimalFormat df = new DecimalFormat("#.##"); 
System.out.println(df.format(l2)); 

此输出

1234567879123456789 
+0

感谢您的详细解答。很多新的东西给我。 – RandomQuestion

+0

不知道ulp。很好的答案!+1 – fge

+0

边栏问题,我们在这里:'StrictMath'也有'ulp()'方法,这些和'Math'有区别吗? – fge

0

你的文字有19个十进制数字,但双只具有精度15.9小数位数。

相关问题