首页 > 解决方案 > 将 numpy 数组的实部和虚部元素四舍五入,向零或远离零四舍​​五入

问题描述

我有一个复数的 numpy 数组,需要创建一个具有四舍五入实部和虚部的新数组,其中一半的舍入要么接近零,要么远离零。

关于使用该包的 stackoverflow 有几项建议,这些建议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_HALF_UP和的确切含义ROUND_HALF_DOWN如下所示:https ://docs.python.org/3/library/decimal.html#decimal.ROUND_HALF_UP 。

非常清楚,为了从零舍入或向零舍入,比如复数的实部,我寻求(注意两半的差异)

      toward zero(ROUND_HALF_DOWN) away from zero (ROUND_HALF_UP)
-4.00         -4.0                 -4.0
-3.75         -4.0                 -4.0
-3.50         -3.0                 -4.0
-3.25         -3.0                 -3.0
-3.00         -3.0                 -3.0
-2.75         -3.0                 -3.0
-2.50         -2.0                 -3.0
-2.25         -2.0                 -2.0
-2.00         -2.0                 -2.0
-1.75         -2.0                 -2.0
-1.50         -1.0                 -2.0
-1.25         -1.0                 -1.0
-1.00         -1.0                 -1.0
-0.75         -1.0                 -1.0
-0.50         -0.0                 -1.0
-0.25         -0.0                 -0.0
 0.00          0.0                  0.0
 0.25          0.0                  0.0
 0.50          0.0                  1.0
 0.75          1.0                  1.0
 1.00          1.0                  1.0
 1.25          1.0                  1.0
 1.50          1.0                  2.0
 1.75          2.0                  2.0
 2.00          2.0                  2.0
 2.25          2.0                  2.0
 2.50          2.0                  3.0
 2.75          3.0                  3.0
 3.00          3.0                  3.0
 3.25          3.0                  3.0
 3.50          3.0                  4.0
 3.75          4.0                  4.0
 4.00          4.0                  4.0

How to always round up a XX.5 in numpy的公认解决方案既慢又不提供我感兴趣的舍入类型。

标签: pythonnumpyrounding

解决方案


链接答案背后的想法合理的,但并没有真正矢量化任何东西。让我们看一下,它向零舍入。这意味着,你想得到。为你想做的。这可以使用矢量化操作来完成,例如np.vectorizeROUND_HALF_DOWNx >= 0ceil(x - 0.5)x < 0floor(x + 0.5)

mask = (x >= 0)
output = x.copy()
np.add(output, -0.5, where=mask, out=output)
np.add(output, 0.5, where=~mask, out=output)
np.ceil(output, where=mask, out=output)
np.floor(output, where=~mask, out=output)

更占用空间,但不那么冗长:

mask = (x >= 0)
output = np.empty_like(x)
output[mask] = np.ceil(x[mask] - 0.5)
output[~mask] = np.floor(x[~mask] + 0.5)

要就地执行操作,只需操作 onx而不是output. 第二部分是分别处理数组的实部和虚部。对于连续数组,这很容易通过视图完成,例如:

x = x.view(np.float)

您可以使用

x = x.view(np.complex)

如果您的数组不连续,最好的办法是分别处理实部和虚部。x.real并且x.imag是数据的视图,因此您可以就地操作它。

TL;博士

def round_half_down(arr):
    output = arr.copy().view(np.float)   # This won't fail because the copy is contiguous
    mask = (output >= 0)
    np.subtract(output, 0.5, where=mask, out=output)
    np.ceil(output, where=mask, out=output)
    np.invert(mask, out=mask)
    np.add(output, 0.5, where=mask, out=output)
    np.floor(output, where=mask, out=output)
    return output.view(np.complex)

推荐阅读