我能想到的最好的就是这个
char a, b, c;
std::cin >> a >> b >> c;
if (((b-a) | (c-a)) & 0x80) {
// a > b || a > c
}
gcc -O2 只生成一个条件分支
40072e: 29 c8 sub %ecx,%eax
400730: 29 ca sub %ecx,%edx
400732: 09 d0 or %edx,%eax
400734: a8 80 test $0x80,%al
400736: 74 17 je 40074f <main+0x3f>
这利用了输入值的约束,因为这些值不能大于 26,所以当 a > b 时,从 b 中减去 a 会给你一个负值,在二进制补码中你知道位 7 会在这种情况下设置 - 这同样适用于 c。然后我 OR 两者,以便位 7 指示是否为 a > b || a > c,最后我们通过 AND 检查位 7 与 0x80 并在其上进行分支。
更新:出于好奇,我对 4 种不同的编码方式进行了计时。为了生成测试数据,我使用了一个简单的线性同余伪随机数生成器。我在一个循环中对它进行了 1 亿次迭代。为简单起见,我假设如果条件为真,我们希望将 5 添加到计数器,否则什么也不做。我使用g++ (GCC) 4.6.3 20120306 (Red Hat 4.6.3-2) 在Intel Xeon X5570 @ 2.93GHz 上使用-O2 优化级别对其进行计时。
这是代码(注释掉除一个条件变量之外的所有变量):
#include <iostream>
unsigned myrand() {
static unsigned x = 1;
return (x = x * 1664525 + 1013904223);
}
int main() {
size_t count = 0;
for(size_t i=0; i<100000000; ++i ) {
int a = 1 + myrand() % 26;
int b = 1 + myrand() % 26;
int c = 1 + myrand() % 26;
count += 5 & (((b-a) | (c-a)) >> 31); // 0.635 sec
//if (((b-a) | (c-a)) & 0x80) count += 5; // 0.660 sec
//if (a > std::max(b,c)) count += 5; // 0.677 sec
//if ( a > b || a > c) count += 5; // 1.164 sec
}
std::cout << count << std::endl;
return 0;
}
最快的是修改我的回答中的建议,我们使用符号扩展来生成一个掩码,它是 32 1s 或 32 0s,具体取决于条件是真还是假,并使用它来屏蔽正在添加的5,使其添加 5 或 0。此变体没有分支。时间在每一行的注释中。最慢的是原始表达式( a > b || a > c)。