位操作中[i,j]区间掩码生成公式~0<<j | ((1<<i)-1)原理咨询
拆解位掩码
~0 << j | ((1 << i) - 1) 的原理 嘿,这个位操作的问题我当初刚学的时候也绕了半天,咱们一步步拆解清楚,结合你的代码来理解:
首先明确咱们的核心目标:要生成一个掩码,用它和N做按位与(&)后,能把N的[i,j]位段清零,同时保留其他所有位的原值。这个掩码的特点就是:[i,j]位是0,其他位是1。
第一步:拆分掩码的两个组成部分
假设我们用的是32位有符号整数(C语言里常见的情况),先看每一部分的作用:
1. ~0 << j
~0 在二进制里是所有位都为1的数(因为0的二进制全是0,取反后自然全1)。把它左移j位后:
- 原来的最低
j位会被挤出去,补成0; - 从第
j位到最高位(31位)保持为1。
比如j=5,32位下这个值是0xFFFFFFE0,二进制就是111...11100000(最后5位是0)。
2. (1 << i) - 1
1 << i 是把数字1左移i位,得到一个二进制里只有第i位是1、其余是0的数。再减1之后:
- 第0位到第
i-1位都会变成1; - 第
i位到最高位保持为0。
比如i=2,这个值是0x00000003,二进制就是000...00000011(最后2位是1)。
第二步:按位或(|)组合两个部分
按位或的规则是:只要对应位有一个是1,结果就是1。把上面两个部分组合起来:
- 第一部分的高位(
j位及以上)是1,第二部分的低位(i-1位及以下)是1; - 中间的
i位到j-1位,两个部分都是0,所以组合后这一段还是0。
最终得到的掩码正好是我们需要的:[i,j]位段为0,其余位为1。
结合你的代码看完整流程
现在把这个逻辑套进你的代码里,就一目了然了:
void merge(int N, int M, int i, int j){ int mask = ~0 << j | ((1 << i) - 1); N = N & mask; // 用掩码清掉N的[i,j]位,其他位保留 mask = ~(mask); // 反转掩码:现在[i,j]位是1,其余位是0 M = M & mask; // 用反转后的掩码只保留M的[i,j]位,其他位清零 N = N | M; // 把M的[i,j]位合并到N的对应位置 }
举个8位的具体例子更直观:
- 假设
N=0b10101010,M=0b00110011,i=2,j=5 - 第一步生成的掩码是
0b11100011,N & mask后得到0b10100010(位2-5被清零) - 反转掩码得到
0b00011100,M & mask后得到0b00010000(只保留M的位2-5) - 最后
N | M得到0b10110010,完美完成合并!
内容的提问来源于stack exchange,提问作者Ebb
相关产品推荐
相关产品推荐

