Python 打印输出中的36位补丁(';%.70f';%(0.2+;0.1))

Python 打印输出中的36位补丁(';%.70f';%(0.2+;0.1)),python,floating-point,ieee-754,Python,Floating Point,Ieee 754,我理解为什么在Python 3中0.1+0.2会产生这样的结果: >>> 0.1 + 0.2 0.30000000000000004 …但是我不明白为什么在下面的输出中间有一个36位数的(大部分)非零数字: >>> print('%.70f' % (0.2 + 0.1)) 0.3000000000000000444089209850062616169452667236328125000000000000000000 我确实希望0.1+0.2和二进制IEEE

我理解为什么在Python 3中
0.1+0.2
会产生这样的结果:

>>> 0.1 + 0.2
0.30000000000000004

…但是我不明白为什么在下面的输出中间有一个36位数的(大部分)非零数字:

>>> print('%.70f' % (0.2 + 0.1))
0.3000000000000000444089209850062616169452667236328125000000000000000000
我确实希望0.1+0.2和二进制IEEE 754浮点值之间存在差异,最接近0.1+0.2,但我不明白为什么这种差异会导致36位表示(大约相当于120位精度)


我可以理解错误的精度是否小得多(<53位),或者(明显的)无限精度,可能是由于计算
“%.70f%”(0.2+0.1)
的算法的伪影。但是我无法理解会导致上面显示的36位补丁的错误。

您正在使用的Python实现显然使用IEEE-754 binary64作为浮点值。(这很常见,但Python并不强制执行。)

在这种格式中,数字表示为2的幂的倍数,其中使用的2的特定幂取决于数字的大小。(浮点格式也以数学上与此等效的其他方式进行了描述,例如使用具有固定小数位数的有效位,而不是我在这里使用的整数倍。此描述更易于解释。)

对于0.3左右的数字,使用2的幂为2−54在四舍五入以适应浮点格式后,添加
.1
.2
的结果是5404319552844596乘以2−54或5404319552844596/254


该数字5404319552844596/254正好是0.300000000004440892909850062616169452667236328125。

粗略地说,输出精确值所需的小数位数与浮点中的位数相同。果然,这个数字有52个有效数字。@MarkRansom:这是一个有趣的经验法则。它适用于除10以外的其他基数吗?它适用于2的倍数的任何基数。基数10是2*5,所以它可以工作,基数6也是,因为它是2*3。7号基地不会,但14号基地会。@MarkRansom:太神奇了。我只是用几个不同的偶数基进行了测试。基于这些测试,我将稍微修改规则,使其“表示中的位数最多与浮点中的位数相同”。不过,我还是被这条规则弄糊涂了。它为什么有效?也许这应该是一个单独的问题…这很可能是一个有趣的阅读:@kjo:对,你是。我从我做的一些工作中复制并粘贴了错误的东西。