【问题标题】:Round real and imaginary elements of numpy array with halves rounded toward zero or away from zero将 numpy 数组的实部和虚部元素四舍五入,向零或远离零四舍​​五入
【发布时间】:2020-06-30 19:25:46
【问题描述】:

我有一个 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 的公认解决方案既慢又不提供我感兴趣的舍入类型。

【问题讨论】:

  • 加/减一半并截断
  • np.fix、np.ceil 和 np.floor 是否有理由不满足您的需求?
  • “请留下评论而不是投票来结束这个问题”不是一个好写的东西。这意味着您知道您的问题有问题。请写一个问题,其质量排除了此类免责声明的必要性,否则您可能会被关闭。
  • @MadPhysicist 我相信以前的版本已关闭,因为有些人不理解这个问题。如果不清楚,我打算有机会首先澄清问题。
  • @rhz。我强烈建议您删除免责声明并确保您遵守网站规则。请记住,人们在这里免费帮助您。你的工作是提出正确的问题,而不是指导他们投票或结束。

标签: python numpy rounding


【解决方案1】:

linked answer 背后的想法 是合理的,但 np.vectorize 并没有真正矢量化任何东西。让我们看一下ROUND_HALF_DOWN,它向零舍入。这意味着对于x >= 0,您想要获得ceil(x - 0.5)。对于x < 0,你想做floor(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)

要就地执行操作,只需对x 进行操作,而不是output。第二部分是分别处理数组的实部和虚部。对于连续数组,这可以通过视图轻松完成,例如:

x = x.view(np.float)

你可以转换回来

x = x.view(np.complex)

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

TL;DR

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)

【讨论】:

  • @rhz。是的,对于问题的第一部分,我使用了x,然后切换到arr。它们都代表您要使用的数组。
  • 对不起,我的意思是说在 TL;DR 下,您的意思是放置 mask = (output >= 0) 而不是 mask = (arr >= 0),对吧?
  • @rhz。出色的抓地力。谢谢你。固定
  • 请注意,有一些浮点极端情况需要注意。这些对 OP 来说可能无关紧要。例如,如果 x = 5000000000000001.0(可以精确表示为 IEEE 754 binary64 浮点数),则 ceil(x - 0.5) 的计算结果为 5000000000000000.0,因为 x - 0.5 不能 精确表示,因此是四舍五入的,并且然后将该舍入结果传递给ceil 操作。 floor(x + 0.5) 也有类似的问题,用于正面的 x(例如,它将 0.49999999999999994 舍入到 1.0)。
  • @MarkDickinson。这些都是极好的点。目标是设置 OP 以矢量化方式处理此问题。您可以通过为|x| > 499999....9(或始终为整数的数字的实际阈值是什么)添加掩码来添加批量特殊情况处理,并为与最近的 0.5 奇数倍差在 1e 以内的数字添加掩码 - 15个左右。我怀疑即使是这样的操作也会比使用np.vectorize 便宜,希望 OP 现在可以弄清楚如何去做。
猜你喜欢
  • 1970-01-01
  • 2017-09-02
  • 2011-07-16
  • 1970-01-01
  • 2023-01-12
  • 2023-03-30
  • 2012-08-04
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多