检测某些整数是否具有特定值的位技巧

pla*_*cel 16 c++ optimization performance x86 bit-manipulation

是否有任何聪明的位技巧来检测是否有少数整数(比如3或4)具有特定值?

直截了当

bool test(int a, int b, int c, int d)
{
    // The compiler will pretty likely optimize it to (a == d | b == d | c == d)
    return (a == d || b == d || c == d);
}
Run Code Online (Sandbox Code Playgroud)

在GCC汇编到

test(int, int, int, int):
        cmp     ecx, esi
        sete    al
        cmp     ecx, edx
        sete    dl
        or      eax, edx
        cmp     edi, ecx
        sete    dl
        or      eax, edx
        ret
Run Code Online (Sandbox Code Playgroud)

这些sete指令有较高的延迟比我要忍受,所以我宁愿用一些按位(&,|,^,~)的东西,比较单一.

Iły*_*sov 5

我发现的唯一解决方案是:

int s1 = ((a-d) >> 31) | ((d-a) >> 31);
int s2 = ((b-d) >> 31) | ((d-b) >> 31);
int s3 = ((c-d) >> 31) | ((d-c) >> 31);

int s = s1 & s2 & s3;
return (s & 1) == 0;
Run Code Online (Sandbox Code Playgroud)

替代变体:

int s1 = (a-d) | (d-a);
int s2 = (b-d) | (d-b);
int s3 = (c-d) | (d-c);

int s = (s1 & s2 & s3);
return (s & 0x80000000) == 0;
Run Code Online (Sandbox Code Playgroud)

两者都被翻译成:

mov     eax, ecx
sub     eax, edi
sub     edi, ecx
or      edi, eax
mov     eax, ecx
sub     eax, esi
sub     esi, ecx
or      esi, eax
and     esi, edi
mov     eax, edx
sub     eax, ecx
sub     ecx, edx
or      ecx, eax
test    esi, ecx
setns   al
ret
Run Code Online (Sandbox Code Playgroud)

其中 sete 指令较少,但显然 mov/sub 较多。

更新:正如 BeeOnRope@ 建议的那样 - 将输入变量转换为无符号是有意义的

  • 您是否实际测试并看到这更快?我怀疑它不会。`SETcc` 指令在现代 Intel CPU 上并不是特别慢。(虽然,问题中的代码有潜在的部分寄存器停顿,这取决于您在哪个处理器上运行它。看到 GCC 生成这样的代码,我感到非常惊讶。它应该知道得更好!) (2认同)
  • 有符号上溢/下溢在 C++ 中是未定义的行为,如果数量很大,这可能会触发它。你可以投射到未签名... (2认同)