以下哪一种技术是整数除2的最佳选择,为什么?

技巧1:

x = x >> 1;

技巧2:

x = x / 2;

这里x是整数。


当前回答

查看编译器的输出来帮助您做出决定。我在x86-64上使用 gcc (gcc) 4.2.1 20070719 [FreeBSD]

也可以在godbolt上看到编译器的在线输出。

What you see is the compiler does use a sarl (arithmetic right-shift) instruction in both cases, so it does recognize the similarity between the two expressions. If you use the divide, the compiler also needs to adjust for negative numbers. To do that it shifts the sign bit down to the lowest order bit, and adds that to the result. This fixes the off-by-one issue when shifting negative numbers, compared to what a divide would do. Since the divide case does 2 shifts, while the explicit shift case only does one, we can now explain some of the performance differences measured by other answers here.

C代码与汇编输出:

对于除法,你的输入是

int div2signed(int a) {
  return a / 2;
}

这个编译成

    movl    %edi, %eax
    shrl    $31, %eax            # (unsigned)x >> 31
    addl    %edi, %eax           # tmp = x + (x<0)
    sarl    %eax                 # (x + 0 or 1) >> 1  arithmetic right shift
    ret

shift也是一样

int shr2signed(int a) {
  return a >> 1;
}

输出:

    sarl    %edi
    movl    %edi, %eax
    ret

其他isa即使不能做得更好,也能同样有效地做到这一点。例如GCC For AArch64使用:

        add     w0, w0, w0, lsr 31      // x += (unsigned)x>>31
        asr     w0, w0, 1               // x >>= 1
        ret

其他回答

就CPU而言,位移运算比除法运算快。 然而,编译器知道这一点,并将适当地优化到它可以的程度, 因此,您可以以最有意义的方式编写代码,并且知道您的代码是有意义的 有效地运行。但是请记住,由于前面指出的原因,在某些情况下,无符号整型可以比整型更好地优化。 如果你不需要符号算术,那么不要包含符号位。

查看编译器的输出来帮助您做出决定。我在x86-64上使用 gcc (gcc) 4.2.1 20070719 [FreeBSD]

也可以在godbolt上看到编译器的在线输出。

What you see is the compiler does use a sarl (arithmetic right-shift) instruction in both cases, so it does recognize the similarity between the two expressions. If you use the divide, the compiler also needs to adjust for negative numbers. To do that it shifts the sign bit down to the lowest order bit, and adds that to the result. This fixes the off-by-one issue when shifting negative numbers, compared to what a divide would do. Since the divide case does 2 shifts, while the explicit shift case only does one, we can now explain some of the performance differences measured by other answers here.

C代码与汇编输出:

对于除法,你的输入是

int div2signed(int a) {
  return a / 2;
}

这个编译成

    movl    %edi, %eax
    shrl    $31, %eax            # (unsigned)x >> 31
    addl    %edi, %eax           # tmp = x + (x<0)
    sarl    %eax                 # (x + 0 or 1) >> 1  arithmetic right shift
    ret

shift也是一样

int shr2signed(int a) {
  return a >> 1;
}

输出:

    sarl    %edi
    movl    %edi, %eax
    ret

其他isa即使不能做得更好,也能同样有效地做到这一点。例如GCC For AArch64使用:

        add     w0, w0, w0, lsr 31      // x += (unsigned)x>>31
        asr     w0, w0, 1               // x >>= 1
        ret

X = X / 2;是合适的代码使用..但是一个操作取决于你自己的程序,你想要产生怎样的输出。

X/Y是正确的…和" >> "移位运算符..如果我们想要二除一个整数,我们可以使用(/)被除数运算符。移位运算符用于移位位。

x = x / 2; x / = 2;我们可以这样用…

Mod 2, test for = 1。不知道c中的语法,但这可能是最快的。