在Python底数划分中舍入错误 [英] rounding errors in Python floor division

查看:100
本文介绍了在Python底数划分中舍入错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道在浮点运算中会发生舍入错误,但是有人可以解释这一原因:

I know rounding errors happen in floating point arithmetic but can somebody explain the reason for this one:

>>> 8.0 / 0.4  # as expected
20.0
>>> floor(8.0 / 0.4)  # int works too
20
>>> 8.0 // 0.4  # expecting 20.0
19.0

在x64上的Python 2和3上都会发生这种情况.

This happens on both Python 2 and 3 on x64.

据我所见,这可能是//的错误或非常愚蠢的规范,因为我看不出最后一个表达式的值应为19.0的任何原因.

As far as I see it this is either a bug or a very dumb specification of // since I don't see any reason why the last expression should evaluate to 19.0.

为什么a // b不能简单地定义为floor(a / b)?

Why isn't a // b simply defined as floor(a / b) ?

编辑:8.0 % 0.4的计算结果也为0.3999999999999996.至少这是必然的,因为随后8.0 // 0.4 * 0.4 + 8.0 % 0.4评估为8.0

EDIT: 8.0 % 0.4 also evaluates to 0.3999999999999996. At least this is consequent since then 8.0 // 0.4 * 0.4 + 8.0 % 0.4 evaluates to 8.0

编辑:这不是浮点运算是否被破坏了?,因为我在问为什么此特定操作会出现(可能是可以避免的)舍入错误,以及为什么a // b未定义为/等于floor(a / b)

EDIT: This is not a duplicate of Is floating point math broken? since I am asking why this specific operation is subject to (maybe avoidable) rounding errors, and why a // b isn't defined as / equal to floor(a / b)

注释:我想这不起作用的更深层原因是楼层划分是不连续的,因此具有无限的

REMARK: I guess that the deeper reason why this doesn't work is that floor division is discontinuous and thus has an infinite condition number making it an ill-posed problem. Floor division and floating-point numbers simply are fundamentally incompatible and you should never use // on floats. Just use integers or fractions instead.

推荐答案

您和khelwood已经注意到,0.4不能完全表示为浮点数.为什么?它是五分之二(4/10 == 2/5),没有有限的二进制分数表示形式.

As you and khelwood already noticed, 0.4 cannot be exactly represented as a float. Why? It is two fifth (4/10 == 2/5) which does not have a finite binary fraction representation.

尝试一下:

from fractions import Fraction
Fraction('8.0') // Fraction('0.4')
    # or equivalently
    #     Fraction(8, 1) // Fraction(2, 5)
    # or
    #     Fraction('8/1') // Fraction('2/5')
# 20

但是

Fraction('8') // Fraction(0.4)
# 19

在这里,0.4被解释为需要(二进制)舍入的浮点文字(因此是浮点二进制数),并且只有 then 转换为有理数Fraction(3602879701896397, 9007199254740992)几乎但不是完全等于4/10.然后执行地板除法,并且因为

Here, 0.4 is interpreted as a float literal (and thus a floating point binary number) which requires (binary) rounding, and only then converted to the rational number Fraction(3602879701896397, 9007199254740992), which is almost but not exactly 4 / 10. Then the floored division is executed, and because

19 * Fraction(3602879701896397, 9007199254740992) < 8.0

20 * Fraction(3602879701896397, 9007199254740992) > 8.0

结果是19,而不是20.

the result is 19, not 20.

可能同样发生

8.0 // 0.4

即,似乎地板分割是原子确定的(但仅基于解释的float文字的近似float值).

I.e., it seems floored division is determined atomically (but on the only approximate float values of the interpreted float literals).

那为什么呢

floor(8.0 / 0.4)

给出正确"的结果?因为在那里,两个舍入误差彼此抵消. First 1)执行除法,生成的东西略小于20.0,但不能表示为float.它四舍五入到最接近的浮点数,恰好是20.0.仅执行 then ,floor操作,但是现在可以精确地作用于 20.0,因此不再更改数字.

give the "right" result? Because there, two rounding errors cancel each other out. First 1) the division is performed, yielding something slightly smaller than 20.0, but not representable as float. It gets rounded to the closest float, which happens to be 20.0. Only then, the floor operation is performed, but now acting on exactly 20.0, thus not changing the number any more.

1)作为Kyle Strand

1) As Kyle Strand points out, that the exact result is determined then rounded isn't what actually happens low2)-level (CPython's C code or even CPU instructions). However, it can be a useful model for determining the expected 3) result.

2)最低 4)级别,这可能并不太遥远.一些芯片组首先通过计算更精确的(但仍然不精确,只是具有更多的二进制数字)内部浮点结果,然后舍入为IEEE双精度来确定浮点结果.

2) On the lowest 4) level, however, this might not be too far off. Some chipsets determine float results by first computing a more precise (but still not exact, simply has some more binary digits) internal floating point result and then rounding to IEEE double precision.

3)是Python规范预期"的,不一定是我们的直觉.

3) "expected" by the Python specification, not necessarily by our intuition.

4)嗯,最低级别的上方逻辑门.我们不必考虑使半导体成为可能的量子力学.

4) Well, lowest level above logic gates. We don't have to consider the quantum mechanics that make semiconductors possible to understand this.

这篇关于在Python底数划分中舍入错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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