由于答案取决于您的架构,让我们看看在 x86-64(使用 gcc -O3)上生成的代码:
#include <math.h>
int t_gt(int x) { // note! not equivalent to the others
return abs(x) > 1;
}
int t_ge(int x) {
return abs(x) >= 1;
}
int t_ne(int x) {
return abs(x) != 1;
}
变成:
Disassembly of section .text:
0000000000000000 <t_gt>:
#include <math.h>
int t_gt(int x) {
0: 89 f8 mov %edi,%eax
2: c1 f8 1f sar $0x1f,%eax
5: 31 c7 xor %eax,%edi
7: 29 c7 sub %eax,%edi
9: 31 c0 xor %eax,%eax
b: 83 ff 01 cmp $0x1,%edi
e: 0f 9f c0 setg %al
return abs(x) > 1;
}
11: c3 retq
12: 66 66 66 66 66 2e 0f nopw %cs:0x0(%rax,%rax,1)
19: 1f 84 00 00 00 00 00
0000000000000020 <t_ge>:
int t_ge(int x) {
20: 89 f8 mov %edi,%eax
22: c1 f8 1f sar $0x1f,%eax
25: 31 c7 xor %eax,%edi
27: 29 c7 sub %eax,%edi
29: 31 c0 xor %eax,%eax
2b: 85 ff test %edi,%edi
2d: 0f 9f c0 setg %al
return abs(x) >= 1;
}
30: c3 retq
31: 66 66 66 66 66 66 2e nopw %cs:0x0(%rax,%rax,1)
38: 0f 1f 84 00 00 00 00
3f: 00
0000000000000040 <t_ne>:
int t_ne(int x) {
40: 89 f8 mov %edi,%eax
42: c1 f8 1f sar $0x1f,%eax
45: 31 c7 xor %eax,%edi
47: 29 c7 sub %eax,%edi
49: 31 c0 xor %eax,%eax
4b: 83 ff 01 cmp $0x1,%edi
4e: 0f 95 c0 setne %al
return abs(x) != 1;
}
51: c3 retq
如您所见,有两个区别:
- set* 操作上的条件代码不同。这可能不会影响速度。
- 对于 t_ge,使用两字节寄存器测试 (AND),而其他两个使用 cmp(减法)和文字单字节操作数进行比较。
虽然各种 set* 变体之间以及 test 和 cmp 之间的差异可能为零,但 cmp 的附加一字节操作数可能会大大降低性能。
当然,完全摆脱无意义的 abs() 可以获得最佳性能:
0000000000000060 <t_ne2>:
int t_ne2(int x) {
60: 31 c0 xor %eax,%eax
62: 85 ff test %edi,%edi
64: 0f 95 c0 setne %al
return (x != 0);
}
67: c3 retq
请记住,这些发现可能不适用于其他架构;但是在任何地方失去腹肌肯定会更快。