在研究python内置浮点函数时,我读了the floating point doc。并得到了一些了解。
0.1
的实际值为'0.1000000000000000055511151231257827021181583404541015625'
但在做了一堆实验后,我仍然遇到一些未解决的疑问。
在我在第一段中提到的教程文档中,它给了我们一个例子:
>>> sum([0.1] * 10) == 1.0
False
>>> math.fsum([0.1] * 10) == 1.0
True
根据文档的说明,我得到的印象是math.fsum
在进行浮点求和时会给出更准确的结果。
但我在range(20)
中发现了一个特殊情况,其中sum([0.1] * 12) == 1.2
evals True,同时math.fsum([0.1] * 12) == 1.2
evals False。这让我感到困惑。
为什么会这样?
进行浮点求和时sum
的机制是什么?
我找到了一些浮点计算,加上运算与它的等效乘法运算具有相同的效果。例如0.1+0.1+0.1+0.1+0.1
等于0.1*5
。但在某些情况下,没有相同的内容,例如加0.1
12次不等于0.1*12
。这让我很困惑。按照浮点数是由IEEE-754标准计算的固定值。根据数学原理,这种加法应该等于它的等价乘法。唯一的解释是python没有在这里完全应用数学原理,一些棘手的事情发生了。
但是这个棘手的东西的机制和细节是什么?
In [64]: z = 0
In [64]: z = 0
In [65]: 0.1*12 == 1.2
Out[65]: False
In [66]: for i in range(12):
...: z += 0.1
...:
In [67]: z == 1.2
Out[67]: True
In [71]: 0.1*5 == 0.5
Out[71]: True
In [72]: z = 0
In [73]: for i in range(5):
...: z += 0.1
...:
In [74]: z == 0.5
Out[74]: True
答案 0 :(得分:1)
当.1转换为64位二进制IEEE-754浮点时,结果正好是0.1000000000000000055511151231257827021181583404541015625。当您单独添加12次时,在添加期间会发生各种舍入错误,最终总和恰好是1.1999999999999999555910790149937383830547332763671875。
巧合的是,当1.2转换为浮点时,结果也正好是1.1999999999999999555910790149937383830547332763671875。这是巧合,因为添加.1的一些舍入误差向上舍入,有些向下舍入,最终产生了1.1999999999999999555910790149937383830547332763671875。
但是,如果.1转换为浮点数然后使用精确数学加法12次,则结果正好是1.20000000000000006661338147750939242541790008544921875。 Python的math.fsum
可能在内部生成此值,但它不适合64位二进制浮点数,因此它舍入为1.20000000000000017763568394002504646778106689453125。
正如您所看到的,更准确的值1.20000000000000017763568394002504646778106689453125与将1.2直接转换为浮点数的结果不同,因此比较报告它们是不相等的。
在this answer中,我逐步添加.1以详细检查舍入错误。