假设我有一个掩码mask
和一个输入n
,例如
mask = 0x10f3 (0001 0000 1111 0011)
n = 0xda4d (1101 1010 0100 1101)
我希望 1)隔离屏蔽位(从n
中删除不在mask
中的位)
masked_n = 0x10f3 & 0xda4d = 0x1041 (0001 0000 0100 0001)
和 2)“展平”它们(摆脱mask
中的零位并将这些相同的转移应用到masked_n
)?
flattened_mask = 0x007f (0000 0000 0111 1111)
bits to discard (___1 ____ 0100 __01)
first shift ( __ _1__ __01 0001)
second shift ( __ _101 0001)
result = 0x0051 (0000 0000 0101 0001)
a)对于这种情况,可以制作一系列特定的位移:
result = (n & 0b10) | (n & 0b11110000) >> 2 | (n & 0b1000000000000) >> 6
b)更一般地说,也可以迭代mask
的每个位并一次计算result
一位。
for (auto i = 0, pos = 0; i < 16; i++) {
if (mask & (1<<i)) {
if (n & (1<<i)) {
result |= (1<<pos);
}
pos++;
}
}
有没有一种更有效的方式来执行此操作,或者至少是临时的,但是无论位置如何都会有固定数量的操作?
答案 0 :(得分:1)
一种更有效的通用方法是循环使用位,但只处理掩码中的位数,从循环中删除if (mask & (1<<i))
测试,仅循环7次而不是16次为例面具。在循环find the rightmost bit of the mask的每次迭代中,用n测试它,在结果中设置相应的位,然后从掩码中删除它。
int mask = 0x10f3;
int n = 0xda4d;
int result = 0;
int m = mask, pos = 1;
while(m != 0)
{
// find rightmost bit in m:
int bit = m & -m;
if (n & bit)
result |= pos;
pos <<= 1;
m &= ~bit; // remove the rightmost bit from m
}
printf("%04x %04x %04x\n", mask, n, result);
输出:
10f3 da4d 0051
或者,可能不太可读,但没有bit
临时变量:
if (n & -m & m)
result |= pos;
pos <<= 1;
m &= m-1;
它是如何工作的?首先,考虑为什么m &= m-1
清除最右边(最不重要)的设置位。你的(非零)掩码m将由一定数量的位组成,然后在最低有效位置中为1,然后为0或更多0:
e.g:
xxxxxxxxxxxx1000
减1给出:
xxxxxxxxxxxx0111
因此,所有高于最低有效设置位的位都将保持不变(因此将它们连接在一起使它们保持不变),最低有效位设置位从1变为0,而较低有效位则预先全部为0将它们与所有1进行对比使它们保持不变。净结果:清除最低有效设置位,其余字保持不变。
理解为什么m&amp; -m给出最低有效位集,将上述内容与2s补码中的知识相结合,-x = ~(x-1)