文字与计算的浮点精度

时间:2015-02-15 16:39:46

标签: java floating-point numbers

我想知道为什么Java中的浮点数在初始化为文字时可以表示精确值,但是当它们表示某些计算结果时它们是近似值。 例如:

double num1 = 0.3;
double num2 = 0.1 + 0.2;
System.out.println(num1);
System.out.println(num2);

结果为何:

0.3
0.30000000000000004

而不是:

0.30000000000000004
0.30000000000000004

当没有精确的二进制表示为0.3时。 我知道BigDecimal类,但我不太明白这个原始数字不一致。

3 个答案:

答案 0 :(得分:4)

这三个数字中没有一个可以完全表示为double。您获得不同结果的原因是,将0.1添加到0.2后的值与0.3的表示错误不同。大约5.5E-17的差异足以在打印出结果时产生差异(demo)。

double a = 0.2;
double b = 0.1;
double c = 0.3;
double d = a+b;
double e = d-c; //  This is 5.551115123125783E-17

答案 1 :(得分:2)

当0.3被转换为其表示为1和0然后转换回小数时,它舍入为0.3。 但是,当0.1和0.2分别转换为二进制时,误差在加法时相加,以便在总和转换回十进制时显示。 详尽的解释将涉及演示每个数字的IEEE表示以及添加和转换。有点参与,但我希望你有这个想法。

答案 2 :(得分:0)

添加本身无法生成0.3的精确表示,因此打印0.1 + 0.2的结果会产生0.30000000000000004

另一方面,当调用System.out.println(0.3);时,println(double)方法会对结果执行一些舍入:它最终调用Double.toString(double),提到结果是近似的:

  

m或a的小数部分必须打印多少位数?必须至少有一个数字来表示小数部分,并且除此之外必须有多个,但只有多少,更多的数字才能唯一地将参数值与double类型的相邻值区分开来。也就是说,假设x是由该方法为有限非零参数d生成的十进制表示所表示的精确数学值。那么d必须是最接近x的double值;或者如果两个double值同样接近x,那么d必须是其中之一,d的有效位的最低有效位必须为0.

如果使用BigDecimal,可以看到差异:

System.out.println(0.3);  // 0.3
System.out.println(new BigDecimal(0.3));  // 0.299999999999999988897769753748434595763683319091796875