当前位置: 首页 > 面试题库 >

在Python底数划分中舍入错误

解高昂
2023-03-14
问题内容

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

>>> 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和Python 3上都发生。

就我所见,这要么是错误,要么是非常愚蠢的规范,//因为我看不出最后一个表达式的求值理由19.0

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

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

编辑
:这不是浮点数学运算符被破坏吗?因为我在问为什么这个特定的运算会受到(可能是可以避免的)舍入错误,为什么a // b不定义为/等于floor(a / b)

备注
:我想这不起作用的更深层原因是楼层划分是不连续的,因此条件数无限,这使它成为一个不适定的问题。楼层分割和浮点数根本上是不兼容的,并且绝对不要//在浮点数上使用。只需使用整数或分数即可。


问题答案:

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

尝试这个:

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被解释为一个浮动文本(以及因此浮点二进制数)需要(二进制)舍入,并且只有 然后
转化为有理数Fraction(3602879701896397, 9007199254740992),这几乎是但不完全4/10。然后执行地板划分,而且因为

19 * Fraction(3602879701896397, 9007199254740992) < 8.0

20 * Fraction(3602879701896397, 9007199254740992) > 8.0

结果是19,而不是20。

同样的事情可能发生

8.0 // 0.4

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

那为什么

floor(8.0 / 0.4)

给出“正确”的结果?因为在那里,两个舍入错误彼此抵消。 首先
1)进行除法,得到的东西略小于20.0,但不能表示为float。它四舍五入到最接近的浮点数,恰好是20.0。只有到 那时
,该floor操作才被执行,但现在 恰好 作用于该操作20.0,因此不再更改该数字。

1)由于凯尔-斯特兰德指出,该确切的结果确定 不是
什么 实际 发生的低2) -电平(CPython中的C代码,甚至CPU指令)。但是,它对于确定预期的3)结果可能是有用的模型

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

3)由Python规范“预期”,不一定是我们的直觉。

4)那么,逻辑门 上方的 最低水平。我们不必考虑使半导体成为可能的量子力学。



 类似资料:
  • 问题内容: 我是Python的初学者,我有一个问题。 为什么用奇数整数部分四舍五入像5.5、7.5((任何).5)这样的数字正确工作(规则5/4),但是用同一个函数将非奇数整数部分像(任何).5进行四舍五入只返回整数部分?(但是,如果我们在该十进制数上加上一个像0.000000001这样的小数字,它将正常工作) 我的意思是下一个: 返回10,这是正确的。但 返回8,这是不正确的。和 返回9。 为什

  • 问题内容: 我不知道这是否是一个明显的错误,但是在运行Python脚本以更改模拟参数时,我意识到缺少和的结果。在调查中,我注意到以下Python代码: 生成的相同文件的增量= 0.28和0.29,与.57和.58相同,原因是python返回float(29)/ 100为。但这不是系统错误,从某种意义上说,它并不是每个整数都发生的。因此,我创建了以下Python脚本: 而且我看不到发生这种舍入错误的

  • 我是Python的初学者,我有一个问题。 为什么舍入像5.5、7.5、(anyther).5这样的数字用奇数部分应用是正确的(规则5/4),但是用相同的函数舍入像(anyther).5这样的数字用非奇数部分只返回一个整数部分?(但是如果我们在这个十进制数字上加上一个小数字,比如0.00000000001,它就能正常工作了) 我是说下一个: 返回10,它是正确的。但是

  • 问题内容: 在我的课程中,我被告知: 连续值大约在内存中表示,因此使用浮点数进行计算会产生舍入误差。这些是位模式的微小差异。因此,如果和为浮点,则测试是不安全的。 指的是Java。 这是真的?我已经将比较语句与s和s一起使用,并且从未遇到过舍入问题。我从来没有读过类似的教科书。虚拟机肯定占了这一切吗? 问题答案: 是真的。 这是如何在内存中以有限数量的位表示浮点值的固有限制。 例如,该程序显示“

  • 问题内容: 根据Wikipedia的说法,在四舍五入一个负数时,您对绝对数进行了四舍五入。因此,根据这种推理,-3.5将四舍五入为-4。但是当我使用java.lang.Math.round(-3.5)时返回-3。有人可以解释一下吗? 问题答案: 根据javadoc 返回最接近参数的long。通过将结果加1/2,将结果取底,并将结果强制转换为long类型,将结果舍入为整数。换句话说,结果等于表达式的

  • 问题内容: 我需要四舍五入,它应该是两位小数。 尝试了以下内容 28.27 但是期望值仅为28.26。 问题答案: 似乎您需要: