如何有效地替换一组连续的位

How to efficiently replace a contiguous set of bits

假设我有一个二进制数 1001100,我想在 [2, 6).

部分用 1011 代替它

看起来像这样:

Binary: 1001100
Sub:    --1011-
Result: 1010110

我知道可以使用此代码多次重复设置一位:
number |= 1UL << n;

但我想知道是否有一种方法可以更有效地实现这一目标。

让我们考虑一个更一般的问题:你有一个二进制数 a,你想用另一个数 b[=40] 的位替换它的位=],只有当第三个数m对应的位为1时。

针对您的具体问题:

a = 1001100
b = xx1011x
m = 0011110

但是没有必要让m对应一个范围

计算结果 r 的伪代码是

for all i in 0 to 6
  if m[i]=1
     r[i]=a[i]
  else
    r[i]=b[i]  

或等同于

for all i in 0 to 6
  r[i] = (a[i] and (m[i]=1)) or (b[i] and (m[i]=0))

我们可以很容易地从中推断出循环是无用的,并且 表达式

r = (a & m) | (b & ~m)

给出了正确的结果。

请注意,如果你想在特定范围内进行替换 kl (例如在你的情况下为 1 到 5 ), 掩码将是 (2^l - 1) - (2^k - 1) = 2^l - 2^k

所以这是对应的C代码

unsigned int replace_bit(unsigned int a, unsigned int b, int k, int l){
  unsigned int mask=(1<<l) - (1<<k)
  return  (a & mask) | (b & ~mask) ;
}

x86 架构上最有效的方法是使用 PDEP instruction,32 位的内在等价物是

PDEP: unsigned __int32 _pdep_u32(unsigned __int32 src, unsigned __int32 mask);

它的用法思路是

mov  ebx, 1001100b    ; initial value
mov  ecx, 0011110b    ; mask value (=SRC2) - bits to be replaced
mov  edx, 0001011b    ; bits to be inserted (=SRC1) at positions ECX
mov  eax, ecx         ; duplicate mask to EAX
not  eax              ; invert mask
and  ebx, eax         ; mask out bits that will be modified
pdep eax, edx, ecx    ; put bits from ECX to position specified by EDX into EAX
or   eax, ebx         ; merge masked initial value with result of PDEP
==>                   ; result is in EAX

这是 x86 汇编解决方案。
如有必要,将其转换为固有表示。
请记住 PDEP 在 AMD 处理器上有点慢。
此解决方案无需任何条件操作(如跳转)即可工作。