【问题标题】:if else vs math in mapping small sequencesif else 与映射小序列中的数学
【发布时间】:2017-05-06 14:13:29
【问题描述】:

我最近不得不将整数的符号转换为 -1 或 1

我想知道,是通过 if else 语句还是通过计算更快?

#if else#
s == -1 ? -1 : 1

#calculation#
ceil((s + 1) / 2) * 2 - 1

我知道这是一个非常简单的示例,但有时您需要映射更大的间隔,而且直观地说,至少对于较小的间隔,数学运算似乎会更快。

另外,相对速度如何受所用语言的影响(例如 Python 与 C)。

【问题讨论】:

  • 第二种解决方案不起作用。考虑如果s 是最大的正整数会发生什么,然后s+1 溢出并且您有未定义的行为!因此,在可行的解决方案和不可行的解决方案之间,选择可行的解决方案。
  • 我说的是映射范围 -1, 0, 1 到 -1, -1, 1(第一行),如果含糊不清,抱歉
  • @AsoneTuhid:如果我是你,我会将该映射添加到实际问题中。

标签: python c performance if-statement mapping


【解决方案1】:

? 运算符会稍微快一些,因为它涉及的指令数量较少,而且我们现在的处理器通常足够聪明,不会破坏管道,尽管它应该看起来像这样:

int r = (s < 0) ? -1 : 1;

括号是为了清楚起见。

如果s 只能是-1、0 或1,我建议:

int v[] = { -1, 1, 1 };
int r = v[s+1];

这永远不会破坏 CPU 管道。

【讨论】:

  • 考虑到 s 只能有 -1、0 和 1 的值,使用 s
  • 为什么我没有想到数组方法?投赞成票!
  • @AsoneTuhid,两个关系表达式的计算结果都是 0 或 1,OP 想要 -1 或 1。
  • 不错,没想到会比 if/else 快吗?
  • 现在OP已经提供了函数,我想你需要s &lt;= 0{-1, -1, 1}作为数组。
【解决方案2】:

现代编译器并不愚蠢。例如,他们不会为有条件的移动提供愚蠢的不必要的跳跃。 (但这并不是说它们很聪明。)鉴于return x == -1 ? -1 : 1;,Clang 和 GCC 分别产生

sgn:                                    # @sgn
    cmp     edi, -1
    mov     eax, 1
    cmove   eax, edi
    ret

sgn:
    xor     eax, eax
    cmp     edi, -1
    setne   al
    lea     eax, [rax-1+rax]
    ret

这些都很好,但我希望 shift + or 更快。 return (2 * -(x &lt; 0)) + 1; 编译为

sgn:                                    # @sgn
    sar     edi, 30
    or      edi, 1
    mov     eax, edi
    ret

sgn:
    mov     eax, edi
    sar     eax, 31
    or      eax, 1
    ret

分别。这些速度非常快。

在 CPython 上情况并非如此,因为那是一个解释器。

【讨论】:

    【解决方案3】:

    在 Python 中,布尔运算符比数学快 >5 倍:

    %timeit (math.ceil((s + 1) / 2) * 2 - 1)
    # 1000000 loops, best of 3: 381 ns per loop
    
    %timeit (-1 if s < 0 else 1)
    #10000000 loops, best of 3: 70.1 ns per loop
    

    在 Python 中,您还可以使用直接字典查找,这令人惊讶地几乎与布尔 if 一样好:

    d = {-1:-1, 0:-1, 1:1}
    %timeit d[s]
    #10000000 loops, best of 3: 73.8 ns per loop
    

    【讨论】:

      【解决方案4】:

      如果性能真的那么重要,我认为很难击败将 {-1, 0, 1} 转换为 {-1, -1, 1} 的代码

      1. 减去 1。
      2. 提取符号位。

      在 C 中,您可以使用几个内联汇编语句来解决这个问题,具体取决于您的平台。

      这可能会超过等效的三元条件(实际上是s &lt;= 0 ? -1 : 1),因为不正确的分支分支预测会导致 CPU 转储管道。

      对于这样的微优化,您需要通过分析来回答它,建立一个适当的测试框架并将性能测量到适当的统计显着水平。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-17
        相关资源
        最近更新 更多