我试图写一个SWAR比较相等操作,在uint64_t
上工作,假装是uint8_t
的8个'车道'。基于Hacker’s Delight和Bit Twiddling Hacks中的技术,我所取得的最接近的结果如下:
uint64_t compare_eq (uint64_t x, uint64_t y) {
uint64_t xored = x ^ y;
uint64_t mask = 0x7F * 0x0101010101010101ULL;
uint64_t tmp = (xored & mask) + mask;
return ~(tmp | xored | mask);
}
然而,这将0x80
放入匹配的"车道"中,而0x00
放入不匹配的"车道"中,而我希望0xFF
在匹配的"车道"中,0x00
在不匹配的"车道"中。有没有可能不写分支?
为了记录,这只是一个非零字节计算高位的变体(少一条指令),加上@njuffa和@Nate Eldredge的评论(可能比4386427的答案更有效)。
uint64_t compare_eq (uint64_t x, uint64_t y) {
uint64_t xored = x ^ y;
uint64_t mask = ((((xored >> 1) | 0x8080808080808080) - xored) & 0x8080808080808080);
return (mask << 1) - (mask >> 7);
}
首先,在发布的代码中有一个错误(拼写错误?):
uint64_t mask = 0x7F * 0x0101010101010101ULL;
^^
Missing 0x
一旦你在车道上有0x80或0x00,你可以除以0x80并乘以0xff。
:
uint64_t compare_eq (uint64_t x, uint64_t y) {
uint64_t xored = x ^ y;
uint64_t mask = 0x7F * 0x0101010101010101ULL;
uint64_t tmp = (xored & mask) + mask;
uint64_t res = ~(tmp | xored | mask);
res = res / 0x80;
res = res * 0xff;
return res;
}