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

bug*_*sle 3 python vb.net floating-point

x = 4.2 - 0.1  
Run Code Online (Sandbox Code Playgroud)

vb.net给出了4.1000000000000005
python给出的4.1000000000000005

Excel给出了4.1
calc calc给出4.1

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

Ste*_*all 13

浮动/双精度.

你必须记住二进制,4.1 = 4 + 1/10.1/10是二进制的无限重复和,很像1/9是十进制的无限和.


Est*_*ber 10

>>> x = 4.2 - 0.1 
>>> x
4.1000000000000005

>>>>print(x)
4.1
Run Code Online (Sandbox Code Playgroud)

这是因为内部存储了数字.

计算机代表二进制数字,而不是十进制数字,正如我们人类习惯的那样.对于浮点数,计算机必须近似最接近的二进制浮点值.

今天(2000年11月)几乎所有机器都使用IEEE-754浮点运算,几乎所有平台都将Python浮点数映射到IEEE-754"双精度".754个双打包含的精度53位,所以在输入的计算机努力0.1转化为它可以形式的最接近的部分J/2***N*,其中J恰好含有53位的整数.

如果print是数字,它将显示近似值,截断为正常值.例如,真正的价值0.10.1000000000000000055511151231257827021181583404541015625.

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

>>> from decimal import Decimal
>>> Decimal("4.2") - Decimal("0.1")
Decimal("4.1")
Run Code Online (Sandbox Code Playgroud)

二进制浮点运算有许多这样的惊喜.下面在" 表示错误 "部分中详细解释了"0.1"的问题.有关其他常见惊喜的更完整说明,请参阅浮点危险.

正如接近结尾所说,"没有简单的答案."不过,不要过分警惕浮点数!Python浮点运算中的错误是从浮点硬件继承的,并且在大多数机器上2**53每个操作的顺序不超过1 个.这对于大多数任务来说已经足够了,但是你需要记住它不是十进制算术,并且每次浮点运算都会遇到新的舍入错误.

虽然存在病态情况,但对于大多数临时使用浮点运算,如果您只是将最终结果的显示舍入为您期望的十进制数字,您将看到最终期望的结果.str()通常就足够了,并且为了更好的控制,请参阅格式字符串语法中str.format()方法的格式说明符.