在特殊情况下:是&比...快 %?

时间:2016-11-23 08:53:56

标签: c++ c performance

我看到了answer选择的post

我很惊讶(x & 255) == (x % 256)如果x是无符号整数,我想知道%&的{​​{1}}是否始终替换为x % n是否有意义}和x是一个正整数。

因为这是一个特殊的情况,我作为一个人可以决定,因为我知道程序将处理哪些值而编译器不会。 如果我的程序使用了大量的模运算,我可以获得显着的性能提升吗?

当然,我可以编译并查看反汇编。但这只会回答我对一个编译器/架构的问题。我想知道这原则上是否更快。

2 个答案:

答案 0 :(得分:46)

如果您的整数类型是无符号的,编译器将对其进行优化,结果将是相同的。如果它已签名,则有所不同......

这个程序:

int mod_signed(int i) {
  return i % 256;
}
int and_signed(int i) {
  return i & 255;
}
unsigned mod_unsigned(unsigned int i) {
  return i % 256;
}
unsigned and_unsigned(unsigned int i) {
  return i & 255;
}

将被编译(by GCC 6.2 with -O3; Clang 3.9 produces very similar code)到:

mod_signed(int):
        mov     edx, edi
        sar     edx, 31
        shr     edx, 24
        lea     eax, [rdi+rdx]
        movzx   eax, al
        sub     eax, edx
        ret
and_signed(int):
        movzx   eax, dil
        ret
mod_unsigned(unsigned int):
        movzx   eax, dil
        ret
and_unsigned(unsigned int):
        movzx   eax, dil
        ret

mod_signed的结果程序集不同,因为

  

如果乘法,除法或模数表达式的两个操作数具有相同的符号,则结果为正。否则,结果是否定的。模数运算符号的结果是实现定义的。

和AFAICT,大多数实现都认为模数表达式的结果总是与第一个操作数的符号相同。请参阅this documentation

因此,mod_signed已针对(来自nwellnhof的评论)进行了优化:

int d = i < 0 ? 255 : 0;
return ((i + d) & 255) - d;

逻辑上,我们可以为所有无符号整数证明i % 256 == i & 255,因此,我们可以信任编译器完成其工作。

答案 1 :(得分:2)

我用gcc进行了一些测量,并且 如果/%的参数是一个2的幂的编译时间常量,gcc可以将其转换为相应的位操作。

以下是我的部门基准 What has a better performance: multiplication or division?正如你所看到的那样,除数的运行时间是静态已知的2的幂,明显低于其他静态已知的除数。

因此,如果/%使用静态已知的2次幂参数描述您的算法比位操作更好,请随意选择/%。 使用合适的编译器不应该失去任何性能。