找到一个数字是偶数还是奇数的最快方法是什么?

aks*_*aks 45 c micro-optimization

找到一个数字是偶数还是奇数的最快方法是什么?

ken*_*ytm 57

众所周知

static inline int is_odd_A(int x) { return x & 1; }
Run Code Online (Sandbox Code Playgroud)

效率比

static inline int is_odd_B(int x) { return x % 2; }
Run Code Online (Sandbox Code Playgroud)

但是随着优化器的开启,将会is_odd_B有什么不同is_odd_A?不 - gcc-4.2 -O2我们得到,(在ARM组装中):

_is_odd_A:
    and r0, r0, #1
    bx  lr

_is_odd_B:
    mov r3, r0, lsr #31
    add r0, r0, r3
    and r0, r0, #1
    rsb r0, r3, r0
    bx  lr
Run Code Online (Sandbox Code Playgroud)

我们看到它is_odd_B需要多3个指令is_odd_A,主要原因是因为

((-1) % 2) == -1
((-1) & 1) ==  1
Run Code Online (Sandbox Code Playgroud)

但是,以下所有版本都将生成相同的代码is_odd_A:

#include <stdbool.h>
static inline bool is_odd_D(int x) { return x % 2; }      // note the bool
static inline int  is_odd_E(int x) { return x % 2 != 0; } // note the !=
Run Code Online (Sandbox Code Playgroud)

这是什么意思?优化器通常足够复杂,对于这些简单的东西,最清晰的代码足以保证最佳效率.

  • 更好的是,将参数指定为`unsigned`. (3认同)
  • `x &amp; 1` 在补码系统上会给出错误的答案。对于可以在我们关心的普通 2 补码系统上高效编译的完全可移植代码,您需要使用 unsigned 或 `x % 2 != 0` (2认同)

And*_*Dog 7

通常的方式:

int number = ...;
if(number % 2) { odd }
else { even }
Run Code Online (Sandbox Code Playgroud)

替代方案:

int number = ...;
if(number & 1) { odd }
else { even }
Run Code Online (Sandbox Code Playgroud)

在GCC 3.3.1和4.3.2上测试,两者都具有大约相同的速度(没有编译器优化),因为两者都导致and指令(在x86上编译) - 我知道使用div模数指令会慢得多,因此我没有根本不测试它.


dig*_*ter 6

bool is_odd = number & 1;
Run Code Online (Sandbox Code Playgroud)

  • 如其他答案中所示,"%2"是"正确"的答案,因为无论如何它将在大多数硬件上编译为"&1",并且它显示了代码的正确意图."&1"来自更智能的编译器优化之前的日子. (8认同)
  • 这在使用一个补码的机器上失败. (7认同)
  • @Jason:如果将“ 1”更改为“ 1U”,则在使用补码的机器上成功。 (2认同)

Vic*_*cky 5

如果(x&1)为真,那么它是奇数,否则它是偶数.

  • 这在使用一个补码的机器上失败. (4认同)