【问题标题】:Different round behaviour for Python round on float and numpy.float64浮点数和 numpy.float64 上 Python 轮次的不同轮次行为
【发布时间】:2018-11-12 18:02:07
【问题描述】:

我偶然发现了一个由浮点精度引起的测试失败,并试图理解它。

简而言之:Python3 round 根据类型是 float 还是 numpy.float64 返回不同的值,尽管我认为 float==double==float64 和 Python3 并且 NumPy 应该四舍五入最接近偶数。

这里是例子:

npVal = np.float64(435)/100
pyVal = 435/100
print(round(npVal,1))             // 4.4
print(round(pyVal,1))             // 4.3
print(round(np.float64(pyVal),1)) // 4.4
print(round(float(npVal),1))      // 4.3

我知道 4.35 和 4.4 可能不能完全用 double 表示,但是为什么 numpy round 与 Python 不同,尽管它们都使用相同的数据类型并指定相似的函数?我使用了显式除法来避免输入舍入错误。

我不确定 4.35 的双精度值是多还是少,所以我不能说这些实现中的哪个是(可能是?)错误的。

有一个类似的问题:Strange behavior of numpy.round

有人指出,NumPy“四舍五入到最接近的偶数值”和“Python 2 和 Python 3 之间的行为发生了变化;Python 3 在此处的行为与 NumPy 相同”。

所以两者都应该做同样的事情并四舍五入到最接近的偶数值。所以如果 4.35 是一个精确的浮点数,4.4 是正确的答案,需要两者都返回。

【问题讨论】:

  • 他们都是对的,4.35 在数轴上与4.4 的距离与与4.3 的距离相同。您可以尝试允许更多的小数位数将罐子踢得更远一点。
  • round 的两个实现都应该按照对链接问题的评论中的解释进行舍入:“值得注意的是,这种行为在 Python 2 和 Python 3 之间发生了变化;Python 3 的行为与 NumPy 相同这里。”我在问为什么不是这样?
  • @coldspeed 这不是重复的:另一个问题是关于 Python 2,这个问题使用 print 函数,使用 Python 3 也是如此,它们应该具有相同的行为。跨度>
  • Python 的 round 是正确舍入的(但速度很慢)。 NumPy 不是(但更快)。不同的权衡。 (同意这不是重复的。)
  • @coldspeed:这个问题不是重复的。它说numpy.round 舍入甚至是舍入十进制值之间的值。但是这个问题中的npVal 不能正好在 4.3 和 4.4 之间,因为 4.35 不能用 64 位二进制浮点表示。最接近的可表示值是 4.3499999999999996447286321199499070644378662109375,应该向下取整。

标签: python numpy floating-point rounding


【解决方案1】:

在 IEEE-754 基本 64 位二进制浮点中计算 435/100 得到 4.3499999999999996447286321199499070644378662109375。

当它被四舍五入到小数点后一位最接近的十进制数字时,结果应该是“4.3”。这种情况下的 Python 舍入似乎是正确的。

对于numpy.rounddocumentation 指的是numpy.arounddocumentation 表示“结果也可能令人惊讶,因为……按 10 次方缩放时引入的错误。”因此,numpy.round 可能没有计算 4.3499999999999996447286321199499070644378662109375 到十进制的正确转换,而是执行 64 位二进制浮点乘以 10,由于浮点舍入,结果正好是 43.5,然后@ 987654328@ 将其四舍五入为 44 并将其格式化为“4.4”。

总之,numpy.round 不是一个正确的舍入例程。

【讨论】:

  • 看来你对 numpy 是正确的:据我了解,它会乘以 10^x 然后舍入到 int 并除以的代码:github.com/numpy/numpy/blob/… 这将是唯一可能的实现我能想到的四舍五入。知道 Python3 做了什么吗?
  • @Flamefire:Python一般是依赖底层平台实现的。可以使用小学教授的技术“轻松”将二进制浮点数转换为精确的十进制数,但简单的实现需要比预期更多的时间和内存。高效转换的专业技术已广为人知并已发布,并且越来越多地内置于标准库函数中,例如 C 的 printfscanf。 (有效地做到这一点很有趣,也有点困难。)但我无法根据我自己的知识告诉你任何特定的 Python 实现是做什么的。
  • @Flamefire:在大多数平台上(底层浮点格式可以被识别为 IEEE 754 的平台),CPython 2.7 和 3.1 及更高版本使用专用的正确舍入二进制到十进制和十进制-to-binary 转换,基于 David Gay 的著名代码。关键来源是here
猜你喜欢
  • 2018-06-19
  • 1970-01-01
  • 1970-01-01
  • 2018-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-14
相关资源
最近更新 更多