使用numpy.rint()舍入到最接近的int,与.5不一致

Ben*_*Ben 20 python numpy

numpy的round int似乎与它处理xxx.5的方式不一致

In [2]: np.rint(1.5)
Out[2]: 2.0

In [3]: np.rint(10.5)
Out[3]: 10.0
Run Code Online (Sandbox Code Playgroud)

1.5向上舍入而10.5向下舍入.是否有一个原因?它只是和浮动不准确的神器?

编辑

有没有办法获得所需的功能,其中n.5被四舍五入,即n = 1或n = 1的n + 1?

Sla*_*off 8

因此,这种行为(如评论中所述)是一种非常传统的舍入形式,从圆形半到均匀的方法看.也被称为(根据David Heffernan)作为银行家的四舍五入.numpy围绕此行为的文档意味着它们正在使用这种类型的舍入,但也暗示了numpy与IEEE浮点格式交互的方式可能存在问题.(如下所示)

Notes
-----
For values exactly halfway between rounded decimal values, Numpy
rounds to the nearest even value. Thus 1.5 and 2.5 round to 2.0,
-0.5 and 0.5 round to 0.0, etc. Results may also be surprising due
to the inexact representation of decimal fractions in the IEEE
floating point standard [1]_ and errors introduced when scaling
by powers of ten.
Run Code Online (Sandbox Code Playgroud)

不管是不是这样,老实说我不知道​​.我知道numpy核心的大部分仍然是用FORTRAN 77编写的,早于IEEE标准(1984年制定),但我不知道FORTRAN 77是否足以说明接口是否存在问题.

如果您只是想要整理,那么np.ceil功能(一般的天花板功能)就会这样做.如果您正在寻找相反的方向(总是向下舍入),该np.floor功能将实现此目的.

  • 它与"如何表示浮动"无关,它与所使用的舍入模式有*所有*.有很多可供选择,参见例如http://en.wikipedia.org/wiki/IEEE_floating_point#Rounding_rules (4认同)
  • @Ben你不应该接受这个错误的答案.这些值完全可以表示.圆形者被称为银行家的四舍五入.谷歌一下.正如马克所说,这是有记录的.Slater,您应该了解可以准确表示的值的形式. (4认同)
  • 关于NumPy的'ceil`:这不会做OP想要的.10.1和10.5的上限*均为*11.0. (2认同)

Yan*_*ier 7

Numpy舍入确实向着舍入,但其他舍入模式可以使用操作的组合来表示.

>>> a=np.arange(-4,5)*0.5
>>> a
array([-2. , -1.5, -1. , -0.5,  0. ,  0.5,  1. ,  1.5,  2. ])
>>> np.floor(a)      # Towards -inf
array([-2., -2., -1., -1.,  0.,  0.,  1.,  1.,  2.])
>>> np.ceil(a)       # Towards +inf
array([-2., -1., -1., -0.,  0.,  1.,  1.,  2.,  2.])
>>> np.trunc(a)      # Towards 0
array([-2., -1., -1., -0.,  0.,  0.,  1.,  1.,  2.])
>>> a+np.copysign(0.5,a)   # Shift away from 0
array([-2.5, -2. , -1.5, -1. ,  0.5,  1. ,  1.5,  2. ,  2.5])
>>> np.trunc(a+np.copysign(0.5,a))   # 0.5 towards higher magnitude round
array([-2., -2., -1., -1.,  0.,  1.,  1.,  2.,  2.])
Run Code Online (Sandbox Code Playgroud)

一般来说,形式n.5的数字可以用二进制浮点精确表示(它们是m.1的二进制,0.5 = 2** - 1),但预计到达它们的计算可能不是.例如,10的负权力并不完全代表:

>>> (0.1).as_integer_ratio()
(3602879701896397, 36028797018963968)
>>> [10**n * 10**-n for n in range(20)]
[1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
 0.9999999999999999, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
Run Code Online (Sandbox Code Playgroud)


小智 7

这实际上正是IEEE浮点标准IEEE 754(1985和2008)规定的舍入.它旨在使舍入无偏.在正态概率理论中,两个整数之间的随机数具有零正确N + 0.5的概率,因此无论如何绕过它都无关紧要,因为这种情况永远不会发生.但在实际程序中,数字不是随机的,N + 0.5经常发生.(事实上​​,每当浮点数丢失1位精度时,你必须舍入0.5!)如果你总是将0.5舍入到下一个最大数,那么一堆舍入数的平均值可能略大于未接地数的平均值:这种偏差或漂移会对某些数值算法产生非常不利的影响并使其不准确.

舍入到偶数比舍入到奇数更好的原因是最后一位数保证为零,所以如果你必须除以2并再次舍入,你根本不会丢失任何信息.

总之,这种舍入是数学家能够设计的最好的,你应该在大多数情况下想要它.现在我们需要做的就是让学校开始教给孩子们.


小智 5

给你编辑的答案:

y = int(np.floor(n + 0.5))
Run Code Online (Sandbox Code Playgroud)

  • 这很简单,但似乎对我有用。我还在 np.array 上测试了它:`y = np.floor(arr+0.5).astype(int)` (4认同)

JSh*_*arm 5

Numpy 使用银行四舍五入,因此 0.5 会四舍五入到最接近的偶数。如果您总是想向上舍入 0.5 但向下舍入 0.4:

np.rint(np.nextafter(a, a+1))

或者如果您总是想向下舍入 0.5 和向下舍入 0.4,但向上舍入 0.6:

np.rint(np.nextafter(a, a-1))

np.around注意,如果您想要相同的逻辑但不需要整数,这也适用。

>>> a = np.array([1, 1.5, 2, 2.5, 3, 3.5])
>>> np.rint(a)
array([1., 2., 2., 2., 3., 4.])
>>> np.rint(np.nextafter(a, a+1))
array([1., 2., 2., 3., 3., 4.])
>>> np.rint(np.nextafter(a, a-1))
array([1., 1., 2., 2., 3., 3.])
Run Code Online (Sandbox Code Playgroud)

怎么了? nextafter给出一个方向上的下一个可表示的数字,因此这足以将数字推离“精确”2.5。

ceil请注意,这与和不同floor

>>> np.ceil(a)
array([1., 2., 2., 3., 3., 4.])
>>> np.floor(a)
array([1., 1., 2., 2., 3., 3.])
Run Code Online (Sandbox Code Playgroud)

  • 与将“0.5”添加到一个非常小的数字相比,“nextafter”具有精度损失较少的优点。“copysign”可能仍然相关。 (2认同)