为什么4 * 0.1的浮点值在Python 3中看起来不错,但是3 * 0.1却没有? [英] Why does the floating-point value of 4*0.1 look nice in Python 3 but 3*0.1 doesn't?

查看:287
本文介绍了为什么4 * 0.1的浮点值在Python 3中看起来不错,但是3 * 0.1却没有?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道大多数小数没有精确的浮点数表示(浮点数学是否被破坏?) p>

但是我不明白为什么 4 * 0.1 很好地打印为 0.4 ,但是 3 * 0.1 不是,当
这两个值实际上都有难看的十进制表示形式时:

 >>> 3 * 0.1 
0.30000000000000004
>>> 4 * 0.1
0.4
>>> from decimal import Decimal
>>>十进制(3 * 0.1)
十进制('0.3000000000000000444089209850062616169452667236328125')
>>>十进制(4 * 0.1)
十进制('0.40000000000000002220446049250313080847263336181640625')


解决方案<由于量化(舍入)误差(而 4 * 0.1 == 0.4),简单的答案是因为 3 * 0.1!= 0.3 因为乘以2的幂通常是一个精确操作)。

可以使用 .hex 方法在Python中查看数字的内部表示(基本上是精确的二进制浮点值,而不是基于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。最后的a意味着数字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的float repr 被设计为 round-trippable ,即显示的值应该完全转换为原始值。因此,它不能以完全相同的方式显示 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).

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 little tiny 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. 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却没有?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆