为什么浮点上的简单数学运算会在VB.Net和Python中返回意外(不准确)?

Why do simple math operations on floating point return unexpected (inaccurate) results in VB.Net and Python?

1
x = 4.2 - 0.1

4.1000000000000005VB.NETPython提供了4.1000000000000005

Excel给4.1谷歌给4.1

发生这种情况的原因是什么?


浮动/双精度。

你必须记住,在二进制中,4.1=4+1/10。1/10是一个二进制的无限重复和,就像1/9是一个十进制的无限和。


1
2
3
4
5
6
>>> x = 4.2 - 0.1
>>> x
4.1000000000000005

>>>>print(x)
4.1

这是因为数字是如何在内部存储的。

计算机用二进制代替十进制来表示数字,就像我们人类习惯的那样。对于浮点数,计算机必须近似于最接近的二进制浮点数。

Almost all machines today (November 2000) use IEEE-754 floating point arithmetic, and almost all platforms map Python floats to IEEE-754"double precision". 754 doubles contain 53 bits of precision, so on input the computer strives to convert 0.1 to the closest fraction it can of the form J/2***N* where J is an integer containing exactly 53 bits.

如果您使用cx1〔0〕这个数字,它将显示近似值,截断为正常值。例如,0.1的实际值是0.1000000000000000055511151231257827021181583404541015625

如果你真的需要一个以10为基数的数字(如果你不知道这个问题的答案,你不知道),你可以使用(在python中)decimal.Decimal

1
2
3
>>> from decimal import Decimal
>>> Decimal("4.2") - Decimal("0.1")
Decimal("4.1")

Binary floating-point arithmetic holds many surprises like this. The problem with"0.1" is explained in precise detail below, in the"Representation Error" section. See The Perils of Floating Point for a more complete account of other common surprises.

As that says near the end,"there are no easy answers." Still, don’t be unduly wary of floating-point! The errors in Python float operations are inherited from the floating-point hardware, and on most machines are on the order of no more than 1 part in 2**53 per operation. That’s more than adequate for most tasks, but you do need to keep in mind that it’s not decimal arithmetic, and that every float operation can suffer a new rounding error.

While pathological cases do exist, for most casual use of floating-point arithmetic you’ll see the result you expect in the end if you simply round the display of your final results to the number of decimal digits you expect. str() usually suffices, and for finer control see the str.format() method’s format specifiers in Format String Syntax.


真的没问题。这只是浮动工作的方式(它们的内部二进制表示)。无论如何:

1
2
3
>>> from decimal import Decimal
>>> Decimal('4.2')-Decimal('0.1')
Decimal('4.1')


在vb.net中,可以使用decimal类型来避免此问题:

1
Dim x As Decimal = 4.2D - 0.1D

结果是4.1。