我基本上试图从特定索引处的整数中删除一个位。也就是说,我不想取消/清除这一点;我实际上想剥离它,以便每个更高的位向下移动,替换其位置的相应位。在视觉上,可以将其与从数组中删除元素或从字符串中删除字符进行比较。
为了清楚起见,举例说明:
1011011 (original number)
^ index = 2
0101111 (result)
10000000000000000000000000000001
^ index = 31
00000000000000000000000000000001
1111111111111111111111111111110
^ index = 0
0111111111111111111111111111111
充满自信,我开始转移一些位,并提出了以下Java方法......
public static int removeBit(int num, int i) {
int out = (num >>> (i + 1)) << i;
out |= (num << (32 - i)) >>> (32 - i);
return out;
}
......除了一些极端情况外几乎总是有效:
10000000000000000000000000000001 (= Integer.MAX_VALUE - 1)
^ index = 31, results in:
10000000000000000000000000000001
1011011
^ index = 0, results in:
1111111
换句话说,如果索引是0或31(最小或最高位),我的方法将输出垃圾。
我似乎无法绕过它,这就是我要问的原因:如何删除32位整数中的任意位?
我特别希望用Java(最小的内存和CPU消耗)来实现最高效的方法,因为这个操作必须运行至少几百万次。这就是为什么像“将它转换为字符串,删除字符并将其转换回来”之类的东西是不可能的。
答案 0 :(得分:2)
正如评论中所解释的那样,班次计数翻到了&gt; = 32,这造成了麻烦。
无论如何,让我们找到一种方法。
首先考虑两个“碎片”,低碎片(在原始位置复制,可能在0 ... 31位长之间的任何位置)和高碎片(向下移动一个,也可以在0 ... 31位长之间)。碎片的总长度始终为31。
小件的面具显而易见:~(-1 << i)
这使得高件的面具显而易见:~lowmask << 1
。无论如何,高的部分都会移动,这样就可以转移。
现在剩下的就是把它们和OR一起拿出来,你就得到了
static int removeBit(int x, int i)
{
int mask = ~(-1 << i);
return (x & mask) | ((x >>> 1) & ~mask);
}
抛弃双重否定:
static int removeBit(int x, int i)
{
int mask = -1 << i;
return (x & ~mask) | ((x >>> 1) & mask);
}
答案 1 :(得分:1)
只需掩盖所需的位,无需来回移动
public static int removeBit(int num, int index) {
int mask = (1 << index) - 1;
return ((num & ((~mask) << 1)) >>> 1) | (num & mask);
}
或
public static int removeBit(int num, int index) {
int mask = (1 << index) - 1;
return ((num >>> 1) & ~mask) | (num & mask);
}
答案 2 :(得分:1)
如果使用最少数量的指令很重要,对于这种位混洗,通常最好计算需要切换的位,然后使用异或来应用它。同样在这里,与哈罗德的解决方案相比,这节省了一条指令:
static int removeBit(int x, int i)
{
int mask = -1 << i;
return ((x ^ (x >>> 1)) & mask) ^ x;
}
或
static int removeBit(int x, int i)
{
return (((x ^ (x >>> 1)) >>> i) << i) ^ x;
}