最初这篇文章要求反绵羊和山羊的操作,但我意识到它比我真正需要的更多,所以我编辑了标题,因为我只需要expand-right algorithm,这更简单。我在下面描述的例子仍然相关。
原帖:
我正在试图弄清楚如何进行逆羊和山羊的操作,或者更好的是,扩展右侧翻转。
根据Hacker's Delight,绵羊和山羊的行动可以表示为:
SAG(x, m) = compress_left(x, m) | compress(x, ~m)
根据this site,反向可以通过以下方式找到:
INV_SAG(x, m, sw) = expand_left(x, ~m, sw) | expand_right(x, m, sw)
但是,我找不到expand_left和expand_right函数的任何代码。当然,它们是压缩的反函数,但压缩本身很难理解。
示例:
为了更好地解释我正在寻找的内容,请考虑一组8位,如:
0000abcd
变量a,b,c和d可以是1或0。此外,还有一个重新定位位的掩码。因此,例如,如果掩码为01100101
,则生成的位将按如下方式重新定位:
0ab00c0d
这可以通过逆羊和山羊手术来完成。然而,根据上面提到的网站this section,有一种更有效的方式,他称之为扩展 - 右翻。看着他的网站,我无法弄清楚如何做到这一点。
答案 0 :(得分:2)
这是来自Hacker's Delight的expand_right
,它只是说expand
,但它是right
版本。
unsigned expand(unsigned x, unsigned m) {
unsigned m0, mk, mp, mv, t;
unsigned array[5];
int i;
m0 = m; // Save original mask.
mk = ~m << 1; // We will count 0's to right.
for (i = 0; i < 5; i++) {
mp = mk ^ (mk << 1); // Parallel suffix.
mp = mp ^ (mp << 2);
mp = mp ^ (mp << 4);
mp = mp ^ (mp << 8);
mp = mp ^ (mp << 16);
mv = mp & m; // Bits to move.
array[i] = mv;
m = (m ^ mv) | (mv >> (1 << i)); // Compress m.
mk = mk & ~mp;
}
for (i = 4; i >= 0; i--) {
mv = array[i];
t = x << (1 << i);
x = (x & ~mv) | (t & mv);
}
return x & m0; // Clear out extraneous bits.
}
您可以使用expand_left(x, m) == expand_right(x >> (32 - popcnt(m)), m)
制作left
版本,但这可能不是最佳方式。