Java中的双重算术与等式

Java中的双重算术与等式,java,floating-point,double,floating-accuracy,ieee-754,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 } 有人想解释一下这里发生

(至少对我来说)有个奇怪的地方。此例程打印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
s伪装成
float
s的整数算法有关。此外,是否还有其他具有此属性的基(除了
10
)呢

1.0具有精确的二进制表示。0.1不适用

也许您会问,为什么0.1不存储为尾数1和指数-10?但事实并非如此。它不是十进制数加指数,而是二进制数。所以“乘以10”不是一件自然的事情


对不起,也许最后一部分不清楚。最好将指数看作是位的移位。位的移位不会将像0.1(十进制)这样的无限序列转换为有限序列。

1.0具有精确的二进制表示。0.1不适用

也许您会问,为什么0.1不存储为尾数1和指数-10?但事实并非如此。它不是十进制数加指数,而是二进制数。所以“乘以10”不是一件自然的事情

对不起,也许最后一部分不清楚。最好将指数看作是位的移位。位的任何移位都不会将像0.1(十进制)这样的无限序列转换为有限序列。

Edit
安德鲁纠正了我的错误。谢谢大家!

Java遵循IEEE 754,基数为2,因此它无法正确表示0.1(在IEEE中,它是近似的
0.10000000000000055115123125782702118158340451015625
1.100110010*2^-4
),您可以根据双精度的二进制表示法找到它,如下所示(位
63
=符号,位
62-52
=指数,位
51-0
为尾数):

我被结果迷住了,我想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.1000000000000088817841970012523233890533447265625-1(Java无法精确表示1.1),即
0.1000000000000088817841970012523233890533447265625
,这与Java内部表示0.1的方式不同(
0.1000000000000055511512312578270211815834541015625

如果您想知道为什么减法结果显示为
0.100000000000009
,而“0.1”显示为原样,请进行编辑 我站在安德鲁一边,谢谢你

Java遵循IEEE 754,基数为2,因此它无法正确表示0.1(在IEEE中,它是近似的
0.10000000000000055115123125782702118158340451015625
1.100110010*2^-4
),您可以根据双精度的二进制表示法找到它,如下所示(位
63
=符号,位
62-52
=指数,位
51-0
为尾数):

我被结果迷住了,我想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.1000000000000088817841970012523233890533447265625-1(Java无法精确表示1.1),即
0.1000000000000088817841970012523233890533447265625
,这与Java内部表示0.1的方式不同(
0.1000000000000055511512312578270211815834541015625


如果您想知道为什么减法的结果显示为
0.100000000000009
和“0.1”按原样显示,有一个

这会一直出现在货币计算中。如果您需要精确的数字表示,当然会以没有启用硬件的性能为代价使用。

这会一直出现在货币计算中。如果您需要精确的数字表示,以没有硬件的性能为代价,请使用当然是性能不佳。

这不是常见的双精度/浮点错误吗?你不能用==来比较双精度。请看@theomega:谢谢你的链接,但这仍然不能解释为什么第一种情况有效。它可以。你可以用二进制表示1.0,但不能表示0.1。好吧,你可以用双精度表示,但不能。这就是为什么(11.0-10.0)=1.0但(1.1-1.0)!=0.1当您使用double时。如果您需要此类功能,可以查看BigDecimal。本文档的可能副本应该可以澄清您可能对浮点的许多问题:这不是常见的双精度/浮点错误吗?您根本无法使用==比较double。请参阅@theomega:感谢链接,但这仍然不正确t解释为什么第一种情况有效。它有效。你可以用二进制表示1.0,但不能表示0.1。好吧,你可以,但不能用double。这就是为什么(11.0-10.0)==1.0,但(1.1-1.0)!=0.1当您使用double时。如果您需要此类功能,可以查看BigDecimal。此文档的可能副本应该可以澄清您可能对浮点的许多问题:谢谢,但我一直在寻找原因,我认为@andrew已经回答了。您链接到的线程中的此答案解释了您在此处出错的原因。谢谢,但是我在寻找原因,我想@andrew已经回答了。你链接到的帖子中的这个答案解释了你在这里出错的原因。@PengOne:是的,
0.5
,以及
0.25
0.75
,或者
0.125
。@paulo:是的,我也检查过了。谢谢你的确认。恐怕你很抱歉惯性矩