Why does the floating-point value of 4*0.1 look nice in Python 3 but 3*0.1 doesn#39;t?(为什么 4*0.1 的浮点值在 Python 3 中看起来不错,但 3*0.1 不好看?)
问题描述
我知道大多数小数都没有精确的浮点表示(浮点数学有问题吗?).p>
但我不明白为什么 4*0.1 可以很好地打印为 0.4,但 3*0.1 不是,当这两个值实际上都有丑陋的十进制表示:
>>>3*0.10.30000000000000004>>>4*0.10.4>>>从十进制导入十进制>>>十进制(3*0.1)十进制('0.30000000000000000444089209850062616169452667236328125')>>>十进制(4*0.1)十进制('0.400000000000000002220446049250313080847263336181640625')简单的答案是因为 3*0.1 != 0.3 由于量化(舍入)误差(而 4*0.1== 0.4 因为乘以 2 的幂通常是精确"运算).Python 试图找到可以四舍五入到所需值的最短字符串,因此它可以将 4*0.1 显示为 0.4,因为它们是相等的,但它不能将 3*0.1 显示为 0.3 因为它们不相等.
您可以使用 Python 中的 .hex 方法查看数字的内部表示(基本上是 exact 二进制浮点值,而不是 base-10近似).这有助于解释幕后发生的事情.
>>>(0.1).hex()'0x1.999999999999ap-4'>>>(0.3).hex()'0x1.3333333333333p-2'>>>(0.1*3).hex()'0x1.3333333333334p-2'>>>(0.4).hex()'0x1.999999999999ap-2'>>>(0.1*4).hex()'0x1.999999999999ap-2'0.1 是 0x1.999999999999a 乘以 2^-4.一个"最后表示数字 10 - 换句话说,二进制浮点中的 0.1 非常轻微 比精确"大.值 0.1(因为最终的 0x0.99 向上舍入为 0x0.a).当您将此乘以 4(2 的幂)时,指数会向上移动(从 2^-4 到 2^-2),但数字不会改变,因此 4*0.1 == 0.4.
但是,当您乘以 3 时,0x0.99 和 0x0.a0 (0x0.07) 之间的微小差异会放大为 0x0.15 错误,在最后一个位置显示为一位数错误.这会导致 0.1*3 比 0.3 的舍入值非常轻微大.
Python 3 的浮点 repr 被设计为 round-trippable,也就是说,显示的值应该完全可以转换为原始值(float(repr(f)) == f 对于所有浮点数 f).因此,它不能以完全相同的方式显示0.3和0.1*3,否则两个不同的数字会在往返后最终相同.因此,Python 3 的 repr 引擎选择显示一个带有轻微明显错误的文件.
I know that most decimals don't have an exact floating point representation (Is floating point math broken?).
But I don't see why 4*0.1 is printed nicely as 0.4, but 3*0.1 isn't, when
both values actually have ugly decimal representations:
>>> 3*0.1
0.30000000000000004
>>> 4*0.1
0.4
>>> from decimal import Decimal
>>> Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
>>> Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')
The simple answer is because 3*0.1 != 0.3 due to quantization (roundoff) error (whereas 4*0.1 == 0.4 because multiplying by a power of two is usually an "exact" operation). Python tries to find the shortest string that would round to the desired value, so it can display 4*0.1 as 0.4 as these are equal, but it cannot display 3*0.1 as 0.3 because these are not equal.
You can use the .hex method in Python to view the internal representation of a number (basically, the exact binary floating point value, rather than the base-10 approximation). This can help to explain what's going on under the hood.
>>> (0.1).hex()
'0x1.999999999999ap-4'
>>> (0.3).hex()
'0x1.3333333333333p-2'
>>> (0.1*3).hex()
'0x1.3333333333334p-2'
>>> (0.4).hex()
'0x1.999999999999ap-2'
>>> (0.1*4).hex()
'0x1.999999999999ap-2'
0.1 is 0x1.999999999999a times 2^-4. The "a" at the end means the digit 10 - in other words, 0.1 in binary floating point is very slightly larger than the "exact" value of 0.1 (because the final 0x0.99 is rounded up to 0x0.a). When you multiply this by 4, a power of two, the exponent shifts up (from 2^-4 to 2^-2) but the number is otherwise unchanged, so 4*0.1 == 0.4.
However, when you multiply by 3, the tiny little difference between 0x0.99 and 0x0.a0 (0x0.07) magnifies into a 0x0.15 error, which shows up as a one-digit error in the last position. This causes 0.1*3 to be very slightly larger than the rounded value of 0.3.
Python 3's float repr is designed to be round-trippable, that is, the value shown should be exactly convertible into the original value (float(repr(f)) == f for all floats f). Therefore, it cannot display 0.3 and 0.1*3 exactly the same way, or the two different numbers would end up the same after round-tripping. Consequently, Python 3's repr engine chooses to display one with a slight apparent error.
这篇关于为什么 4*0.1 的浮点值在 Python 3 中看起来不错,但 3*0.1 不好看?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为什么 4*0.1 的浮点值在 Python 3 中看起来不错,但
基础教程推荐
- Python,确定字符串是否应转换为 Int 或 Float 2022-01-01
- Kivy 使用 opencv.调整图像大小 2022-01-01
- kivy 应用程序中的一个简单网页作为小部件 2022-01-01
- matplotlib 设置 yaxis 标签大小 2022-01-01
- 在 Django Admin 中使用内联 OneToOneField 2022-01-01
- Python 中是否有任何支持将长字符串转储为块文字或折叠块的 yaml 库? 2022-01-01
- 在 Python 中将货币解析为数字 2022-01-01
- 究竟什么是“容器"?在蟒蛇?(以及所有的 python 容器类型是什么?) 2022-01-01
- 对多索引数据帧的列进行排序 2022-01-01
- 比较两个文本文件以找出差异并将它们输出到新的文本文件 2022-01-01
