Python 用numpy.rint()四舍五入到最接近的整数与.5不一致

Python 用numpy.rint()四舍五入到最接近的整数与.5不一致,python,numpy,Python,Numpy,似乎与它处理xxx的方式不一致。5 In [2]: np.rint(1.5) Out[2]: 2.0 In [3]: np.rint(10.5) Out[3]: 10.0 1.5四舍五入,10.5四舍五入。这有什么原因吗?这是正义和人为的吗 编辑 有没有一种方法可以在n.5被四舍五入的情况下获得所需的功能,即n=偶数或奇数时均为n+1?因此,这种行为(如注释中所述)是一种非常传统的四舍五入形式,如该方法所示。也被称为(根据大卫·赫弗南的说法)银行家四舍五入。有关此行为的numpy文档表明他们

似乎与它处理xxx的方式不一致。5

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

In [3]: np.rint(10.5)
Out[3]: 10.0
1.5四舍五入,10.5四舍五入。这有什么原因吗?这是正义和人为的吗

编辑

有没有一种方法可以在n.5被四舍五入的情况下获得所需的功能,即n=偶数或奇数时均为n+1?

因此,这种行为(如注释中所述)是一种非常传统的四舍五入形式,如该方法所示。也被称为(根据大卫·赫弗南的说法)银行家四舍五入。有关此行为的
numpy
文档表明他们正在使用这种舍入,但也意味着
numpy
与IEEE浮点格式交互的方式可能存在问题。(如下所示)

不管是不是这样,我真的不知道。我知道大部分的
numpy
内核仍然是用FORTRAN 77编写的,它早于IEEE标准(1984年制定),但我不知道FORTRAN 77是否足以说明这里的接口有问题


如果您想不考虑取整,则
np.ceil
函数(通常为上限函数)将完成此操作。如果您正在寻找相反的结果(总是向下舍入),则
np.floor
函数将实现这一点。

内置的舍入函数似乎可以实现您想要的功能,尽管它仅适用于标量:

def correct_round(x):
    try:
        y = [ round(z) for z in x ]
    except:
        y = round(x)    
    return y
然后验证:

print correct_round([-2.5,-1.5,-0.5,0.5,1.5,2.5])
> [-3.0, -2.0, -1.0, 1.0, 2.0, 3.0]

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.])
一般来说,形式为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]

事实上,这正是IEEE浮点标准(1985年和2008年)规定的舍入。它旨在使舍入无偏。在正态概率理论中,两个整数之间的随机数正是N+0.5的概率为零,所以不管你如何舍入它,因为这种情况永远不会发生。但在实际程序中,数字不是随机的,N+0.5经常出现。(事实上,每当一个浮点数失去1位精度时,必须将0.5四舍五入!)如果总是将0.5四舍五入到下一个最大的数字,然后,一组舍入数的平均值可能略大于未舍入数的平均值:这种偏差或漂移会对某些数值算法产生非常坏的影响,使它们不准确

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

总之,这种四舍五入是数学家们所能设计的最好的方法,在大多数情况下,你应该想要它。现在,我们需要做的就是让学校开始教孩子们学习英语。

回答如下:

y = int(np.floor(n + 0.5))

不确定这是最有效的解决方案,但它确实有效:

signs = np.sign(arr)
tmp = signs * arr
arr = np.floor(tmp + 0.5)
arr = arr * signs

Numpy使用四舍五入,因此.5四舍五入到最接近的偶数。如果你总是想四舍五入。向上五舍五入,向下四舍五入:

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

或者,如果您总是想四舍五入。向下5,向下4,但向上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)
数组([1,2,2,2,3,4.]))
>>>np.rint(np.nextafter(a,a+1))
数组([1,2,2,3,3,4.]))
>>>np.rint(np.nextafter(a,a-1))
数组([1,1,2,2,3,3.]))
发生了什么事?
nextafter
给出一个方向上的下一个可表示数字,因此这足以将数字“精确”推离2.5

注意这与
ceil
floor
不同

np.ceil(a) 数组([1,2,2,3,3,4.])) >>>np.楼层(a) 数组([1,1,2,2,3,3.]))
回答得好,你知道如何让numpy在奇数或偶数情况下进行取整吗?它与“浮点数的表示方式”无关,它与所使用的取整模式有关。有许多选项可供选择,例如@Ben yes,np.ceil将这样做。@Ben你不应该接受这个错误的答案。这些值完全可以表示。取整者被称为银行家取整。谷歌。正如马克所说,这是有记录的。Slater,你应该知道可以精确表示的值的形式。关于NumPy的
ceil
:这不会满足OP的要求。10.1和10.5的上限都是11.0。好吧,总是有Python内置的
舍入
,它舍入一个值,并且从零开始。如果需要对numpy数组中的所有元素进行舍入,那么使用Python的
round
当然会非常慢。但正如Mark Ransom在下面的评论中所指出的,numpy似乎不允许您选择舍入规则。@JohnY Novely Python的
舍入
也舍入到最接近的偶数整数。@KirillBulygin-您提出了一个很好的观点。Python2(包括最新的2.7.x版本)在平局中从零开始循环,而Python3在平局中从零开始循环。这只与Python2相关。参见Python 3文档:
nextafter
与将
0.5
添加到一个非常小的数字相比,具有精度损失少的优势
copysign
可能仍然相关。这很简单,但似乎对我有用。我还在np.array上测试了它:
y=np.floor(arr+0.5).astype(int)
signs = np.sign(arr)
tmp = signs * arr
arr = np.floor(tmp + 0.5)
arr = arr * signs