在 python 中向上或向下舍入一半的快速方法

Fast method to round half up or down in python

我有一个 numpy 复数数组,需要创建一个包含四舍五入的实部和虚部的新数组,其中四舍五入是向零或向无穷大。

在 Whosebug 上有一些关于使用 decimal 包的建议,它允许指定不同类型的舍入。对于复数数组 x,以下代码有效,但速度很慢:

    rounded_array = np.array([
        float(Decimal(x.real).quantize(0, rounding=ROUND_HALF_DOWN)) + 1j * \
        float(Decimal(x.imag).quantize(0, rounding=ROUND_HALF_DOWNs)) for x in arr])

有哪些简单但更快的替代方法? 建议使用此解决方案: 但是,它仅适用于真实数组,并且比下面建议的解决方案慢得多。

您可以 round 独立的实部和虚部,然后从中创建一个新数组:

rounded_array = np.fix(arr.real) + 1j*np.fix(arr.imag)

快速就地舍入减半:

arr = arr.view(float)
m = arr % 1. <= .5
arr[m] = np.floor(arr[m])
arr[~m] = np.ceil(arr[~m])
arr = arr.view(complex)

(使用 m = arr % 1. < .5 取整)

如果您需要一个新数组而不是就地更改现有数组,请将第一行更改为 arr = arr.view(float).copy('K')

对于 1000 个元素的数组,这比原始解决方案快大约 100 倍。


UPDATE 根据以下评论对负数进行更新:

m = arr % 1. == .5
arr[m] = np.trunc(arr[m])
arr[~m] = np.round(arr[~m])

时间

x = np.arange(-1000, 1000, .1)
arr = x + 1j * x

%%timeit
rounded_array = np.array([
        float(Decimal(x.real).quantize(0, rounding=ROUND_HALF_DOWN)) + 1j * \
        float(Decimal(x.imag).quantize(0, rounding=ROUND_HALF_DOWN)) for x in arr])
        
1.83 s ± 27.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
arr1 = arr.view(float).copy('K')
m = arr1 % 1. == .5
arr1[m] = np.trunc(arr1[m])
arr1[~m] = np.round(arr1[~m])
arr1 = arr1.view(complex)


1.78 ms ± 18.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)