round()和numpy.round()之间的内在区别是什么?


问题内容

让我们看一下令人震惊的回合声明:

>>> round(2.675, 2)
2.67

我知道为什么会“失败”;这是因为2.675的二进制表示形式:

>>> import decimal
>>> decimal.Decimal(2.675)
Decimal('2.67499999999999982236431605997495353221893310546875')

我不明白的是: 为什么NumPy不会失败

>>> import numpy
>>> numpy.round(2.675, 2)
2.6800000000000002

思维

不要介意多余的零;这是Python打印内部舍入的伪像。如果我们看一下“精确”值,它们仍然是不同的:

>>> decimal.Decimal(round(2.675, 2))
Decimal('2.6699999999999999289457264239899814128875732421875')

>>> decimal.Decimal(numpy.round(2.675, 2))
Decimal('2.680000000000000159872115546022541821002960205078125')

为什么哦,为什么NumPy会表现?

我最初以为NumPy必须使用额外的位来处理浮点数,但是:

>>> decimal.Decimal(numpy.float(2.675))
Decimal('2.67499999999999982236431605997495353221893310546875')
>>> decimal.Decimal(2.675)
Decimal('2.67499999999999982236431605997495353221893310546875')
# Twins!

幕后发生了什么?我稍微看了看NumPy的全面实现,但是我是Python新手,而且我看不到任何多余的东西。


问题答案:

引擎盖差异最大的一个记录在案:

如果您在数字中间,则np.round四舍五入到最接近的“偶数”数字(乘以10**nwheren是相应round函数的第二个参数),而内建round函数则四舍五入为0。

>>> np.round(2.685, 2)
2.6800000000000002
>>> round(2.685, 2)
2.69

在幕后,使用scaleing参数时可能会有所不同。考虑之间的差异round(2.675 * 10.**2)round(2.675, 2)。当然,这是浮点数学运算的结果,该运算符一如既往具有一些舍入误差。要走得更远,我们确实需要看一下实际的实现。