减去两个十进制数,给出奇怪的输出

时间:2013-09-29 13:24:26

标签: java floating-point

虽然我正在玩Java Puzzlers的代码(我没有这本书)但我遇到了这段代码

public static void main(String args[]) {
        System.out.println(2.00 - 1.10);
    }

输出

0.8999999999999999

当我尝试将代码更改为

2.00d - 1.10d我仍然获得与0.8999999999999999

相同的输出

对于,2.00d - 1.10f输出为0.8999999761581421
对于,2.00f - 1.10d输出为0.8999999999999999
对于,2.00f - 1.10f输出为0.9

为什么我首先得到0.9的输出?我不能用这个做任何头或尾?有人可以清楚说明这一点吗?

3 个答案:

答案 0 :(得分:6)

因为在Java中,双值是IEEE floating point numbers

解决方法可能是使用Big Decimal class

  

不可变,任意精度的带符号十进制数。一个BigDecimal   由任意精度整数非标度值和32位组成   整数尺度。如果为零或正数,则比例为数字位数   小数点右侧。如果为负数,则为未缩放值   数字乘以十来得到否定的力量   规模。 BigDecimal表示的数字的值是   因此(unscaledValue×10 ^ -scale)。

旁注,您可能还想检查Wikipedia article on IEEE 754大多数系统中如何存储浮点数。

您对浮点数执行的操作越多,可能会出现更严重的舍入错误。

答案 1 :(得分:5)

在二进制0.1中是0.00011001100110011001100110011001 .....,

因此无法用二进制表示。根据你四舍五入的地方(浮动或双重),你得到不同的答案。

所以0.1f = 0.000110011001100110011001100 并且0.1d = 0.0001100110011001100110011001100110011001100110011001

您注意到该数字在1100个循环中重复。但是浮动和双精度将它分成循环中的不同点。因此,一个错误四舍五入,另一个回合;导致差异。

但最重要的是; 永远不要假设浮点数是准确的

答案 2 :(得分:1)

其他答案是正确的,只是指向有效的参考,我引用oracle doc

  

double:双精度数据类型是双精度64位IEEE 754   浮点。它的价值范围超出了这个范围   讨论,但在浮点类型,格式和   Java语言规范的值部分。对于十进制值,   此数据类型通常是默认选择。正如刚才提到的,   此数据类型永远不应用于精确值,例如   货币