例如,如果我有数字20:
0001 0100
我想将最高值1位(最左边)设置为0。
所以
0001 0100
将成为
0000 0100
我想知道哪种方法最有效。
最好是在c ++中。
我尝试从原始数字中减去两个这样的最大幂,
unsigned long long int originalNumber;
unsigned long long int x=originalNumber;
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
x >>= 1;
originalNumber ^= x;
,但我需要更高效的东西。
答案 0 :(得分:3)
#include <limits.h>
uint32_t unsetHighestBit(uint32_t val) {
for(uint32_t i = sizeof(uint32_t) * CHAR_BIT - 1; i >= 0; i--) {
if(val & (1 << i)) {
val &= ~(1 << i);
break;
}
}
return val;
}
这里我们取类型uint32_t
的大小,即4个字节。每个字节有8位,因此我们从i
开始迭代32次,值为31到0。
在每次迭代中,我们将值1移动到i
向左,然后按位 - 和(&
)将它移动到我们的值。如果返回值!= 0,则设置i
处的位。一旦我们找到一个设置的位,我们按位和(&
)我们的初始值与设置位的按位求反(~
)。
例如,如果我们有数字44,它的二进制表示将是0010 1100
。我们找到的第一个设置位是第5位,从而产生掩码0010 0000
。该掩码的按位否定为1101 1111
。现在,当使用此掩码按位&
初始值时,我们得到值0000 1100
。
这是一个如何使用模板在C ++中解决这个问题的例子:
#include <limits>
template<typename T> T unsetHighestBit(T val) {
for(uint32_t i = sizeof(T) * numeric_limits<char>::digits - 1; i >= 0; i--) {
if(val & (1 << i)) {
val &= ~(1 << i);
break;
}
}
return val;
}
答案 1 :(得分:3)
如果你被限制为8位(如你的例子中所示),那么只需使用任何算法预先计算数组中的所有可能值(byte [256]),或者只需手动输入。
然后你只需查找所需的值:
x = lookup[originalNumber]
不能比那快得多。 : - )
更新:所以我读错了这个问题。
但是如果使用64位值,则将其分解为8个字节,可以将其分解为一个字节[8]或将其覆盖在一个联合或更聪明的东西中。之后,找到第一个不为零的字节,并按照我上面的回答中的那个特定字节进行操作。我担心效率不高,但最多只有8次测试(平均4.5次)+一次查找。
当然,创建字节[65536}查找会使速度加倍。
答案 2 :(得分:3)
棘手的部分是找到最重要的位,或计算前导零的数量。其他所有东西都可以或多或少地通过左移1(少一个),减1然后否定(构建逆掩码)和&
运算符来完成。
众所周知的bit hacks站点有几个实现找到最重要的位的问题,但它也值得研究编译器内在函数,因为所有主流编译器都有一个内在的用于此目的,他们实现和目标架构一样有效(我几年前在x86上使用GCC进行了测试,结果是单指令)。在没有对目标体系结构进行分析的情况下,哪个是最快的是不可能分辨的(代码行数较少,或者更少的汇编指令并不总是更快!)但是,编译器实现这些内在函数并不比你更糟糕是一个公平的假设。能够实施它们,并且可能更快 使用具有某种可理解名称的内在函数也可能比从现在开始看5年后的某些内容更容易理解。
不幸的是,虽然这并非完全不常见,但这并不是您期望在C或C ++库中找到的标准化功能,至少没有我所知道的标准功能。
对于GCC,您正在寻找__builtin_clz
,VisualStudio将其称为_BitScanReverse
,而英特尔的编译器将其称为_bit_scan_reverse
。
除了计算前导零之外,您可以查看相同的Bit Twiddling网站所拥有的内容&#34;四舍五入到下一个#2的幂,您只需要跟进右移1,和NAND操作。请注意,站点上给出的5步实现是针对32位整数的,您必须将64位宽值的步数加倍。
答案 3 :(得分:0)
以下代码将关闭最右边的位:
bool found = false;
int bit, bitCounter = 31;
while (!found) {
bit = x & (1 << bitCounter);
if (bit != 0) {
x &= ~(1 << bitCounter);
found = true;
}
else if (bitCounter == 0)
found = true;
else
bitCounter--;
}
答案 4 :(得分:-1)
我知道将非正数位设置为0的方法。
a & (a - 1)
来自Book:Warren H.S., Jr. - Hacker's Delight.
您可以反转您的位,将更多权限设置为零并反转。但我现在知道在你的情况下反转位的有效方法。