Java中的双重算术和相等

时间:2011-09-02 21:25:10

标签: java floating-point double floating-accuracy ieee-754

这是一个奇怪的事(至少对我来说)。此例程打印为true:

double x = 11.0;
double y = 10.0;
if (x-y == 1.0) {
    // print true
} else {
    // print false
}

但是这个例程打印错误:

double x = 1.1;
double y = 1.0;
if (x-y == 0.1) {
    // print true
} else {
    // print false
}

有人想解释这里发生了什么吗?我猜它与int冒充float s的整数算术有关。此外,是否还有其他基础(10除外)具有此属性?

3 个答案:

答案 0 :(得分:9)

1.0具有精确的二进制表示。 0.1没有。

也许你在问为什么0.1没有存储为1的尾数和-10的指数?但这不是它的工作原理。它不是十进制数加上指数,而是二进制数。所以“时代10”并不是一件很自然的事情。

抱歉,也许最后一部分不清楚。最好将指数视为位的移位。没有位移位会将0.1(十进制)等无限序列转换为有限序列。

答案 1 :(得分:4)

修改
我被安德鲁纠正了。谢谢!

Java遵循IEEE 754,Base为2,因此它无法正确表示0.1(IEEE中的aprox。0.10000000000000000555111512312578270211815834045410156251.1001100110011001100110011001100110011001100110011010 * 2^-4),您可以根据该二进制表示法找到它。像这样加倍(位63 =符号,位62-52 =指数,位51-0是尾数):

long l = Double.doubleToLongBits(0.1);
System.out.println(Long.toBinaryString(l));

我刚刚被结果带走了,我想了一下,Java中的浮点数正在使用10的基数,在这种情况下,它可能代表0.1就好了。

现在希望一劳永逸地清除这些事情,这里发生了什么:

BigDecimal bigDecimal1 = new BigDecimal(0.1d);
BigDecimal bigDecimal2 = new BigDecimal(1.1d - 1.0);
BigDecimal bigDecimal3 = new BigDecimal(1.1d);
BigDecimal bigDecimal4 = new BigDecimal(1.0d);
System.out.println(bigDecimal1.doubleValue());
System.out.println(bigDecimal2.doubleValue());
System.out.println(bigDecimal3.doubleValue());
System.out.println(bigDecimal4.doubleValue());
System.out.println(bigDecimal1);
System.out.println(bigDecimal2);
System.out.println(bigDecimal3);
System.out.println(bigDecimal4);

输出:

0.1
0.10000000000000009
1.1
1.0
0.1000000000000000055511151231257827021181583404541015625
0.100000000000000088817841970012523233890533447265625
1.100000000000000088817841970012523233890533447265625
1

那会发生什么? 1.1 - 1.0相当于:
1.100000000000000088817841970012523233890533447265625 - 1(Java不能精确地表示1.1),这是0.100000000000000088817841970012523233890533447265625,这与Java在内部表示0.1的方式不同0.1000000000000000055511151231257827021181583404541015625

如果您想知道为什么减法的结果显示为0.10000000000000009和" 0.1"按原样显示,有一个look over here

答案 2 :(得分:0)

这始终是货币计算。如果您需要精确的数字表示,请使用BigDecimal,但代价是没有硬件启用性能。