浮点运算产生的误差

浮点数在计算机硬件中表示为以 2 为基数(二进制)的小数。举例而言,十进制的小数

0.125

等于 1/10 + 2/100 + 5/1000 ,同理,二进制的小数

0.001

等于0/2 + 0/4 + 1/8。这两个小数具有相同的值,唯一真正的区别是第一个是以 10 为基数的小数表示法,第二个则是 2 为基数。

不幸的是,大多数的十进制小数都不能精确地表示为二进制小数。这导致在大多数情况下,输入的十进制浮点数都只能近似地以二进制浮点数形式储存在计算机中。

就像十进制中的 1/3,我们可以用 0.3 或者 0.33 或者 0.333。但是无论你写下多少的数字,它都永远不会等于 1/3 ,只是更加更加地接近 1/3 。

比如十进制的 0.1
无论使用多少位以 2 为基数的数码,十进制的 0.1 都无法精确地表示为一个以 2 为基数的小数。 在以 2 为基数的情况下, 1/10 是一个无限循环小数

0.0001100110011001100110011001100110011001100110011...

大多数情况下,我们会使用字符串格式化来产生限定长度的有效位数:

format(math.pi,".2f")
3.14

这在实际上只是一个假象:你只是将真正的机器码值进行了舍入操作再 显示 而已。
一个假象还可能导致另一个假象。 例如,由于这个 0.1 并非真正的 1/10,将三个 0.1 的值相加也不一定能恰好得到 0.3:

0.1 + 0.1 + 0.1 == 0,3
False

而且,由于这个 0.1 无法精确表示 1/10 的值而这个 0.3 也无法精确表示 3/10 的值,使用 round() 函数进行预先舍入也是没用的:

round(0.1, 1) + round(0.1, 1) + round(0.1, 1) == round(0.3, 1)
False

虽然这些小数无法精确表示其所要代表的实际值,round() 函数还是可以用来“事后舍入”,使得实际的结果值可以做相互比较:

round(.1 + .1 + .1, 10) == round(.3, 10)
True

Python 浮点运算中的错误是从浮点运算硬件继承而来,而在大多数机器上每次浮点运算得到的 2**53 数码位都会被作为 1 个整体来处理。

请注意这种情况是二进制浮点数的本质特性:它不是 Python 的错误,也不是你代码中的错误。 你会在所有支持你的硬件中的浮点运算的语言中发现同样的情况(虽然某些语言在默认状态或所有输出模块下都不会显示这种差异)。

有关浮点风险

猜你喜欢

转载自www.cnblogs.com/zhimao/p/12430335.html