C++ 如何将最高值的1位设置为0,最好在c++;

C++ 如何将最高值的1位设置为0,最好在c++;,c++,algorithm,bit-manipulation,bit,C++,Algorithm,Bit Manipulation,Bit,例如,如果我有数字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

例如,如果我有数字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;

,但我需要更有效的方法。

如果您被限制为8位(如示例中所示),则只需使用任何算法预先计算数组中所有可能的值(字节[256]),或者手动键入即可

#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;
}
然后只需查找所需的值:

   x = lookup[originalNumber]
再快不过了。:-)

更新:所以我把问题看错了

但是如果使用64位值,那么可以将其拆分为8个字节,可以将其强制转换为一个字节[8],或者将其叠加在一个并集中,或者做一些更聪明的事情。在那之后,找到第一个不是零的字节,并按照我上面的答案处理这个特定的字节。恐怕效率不高,但它最多只能进行8次测试(平均4.5次)+一次查找


当然,创建字节[65536}查找将使速度加倍。

我知道将更多右非零位设置为0的方法

a & (a - 1)
它来自于一本书:


您可以反转位,将“更右”设置为零,然后再反转回来。但我现在知道在您的情况下反转位的有效方法。

以下代码将关闭最右边的位:

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--;
}
boolfound=false;
整数位,位计数器=31;
而(!found){

bit=x&(1棘手的部分是找到最重要的位,或者计算前导零的数量。其他的一切都可以通过左移1(少一个)、减去1然后求反(构建反向掩码)和
&
操作符来完成

这家著名的网站针对查找最重要位的问题提供了几种实现,但也值得研究编译器内部函数,因为所有主流编译器都有一个用于此目的的内部函数,它们实现的效率与目标体系结构所允许的一样高(几年前,我在x86上使用GCC测试了这一点,结果是单指令)。如果不在目标体系结构上进行分析,就无法判断哪一条最快(代码行数更少或汇编指令数更少并不总是更快!),但这是一个公平的假设,编译器实现这些本质不会比您实现它们的能力差很多,而且可能更快。
从现在起5年后再看,使用一个具有某种不可理解的名称的内在代码可能比一些小技巧更容易理解

Unluckily,虽然不是一个不寻常的东西,但这不是一个标准化的函数,你希望在C或C++库中找到它,至少我没有意识到标准函数。 对于GCC,您正在寻找

\uu内置clz
,VisualStudio将其称为
\uBitScanReverse
,Intel的编译器将其称为
\uBitScan\uReverse


除了计算前导零外,您还可以在“向上取整到下一个二的幂”下查看同一个位旋转站点的内容,您只需使用右移1和NAND操作即可。请注意,网站上提供的5步实现是针对32位整数的,您必须将64位宽值的步数增加一倍。

您尝试过什么吗?是的,我尝试过使用bitwi从原始数中减去2的最高幂se来计算最高幂。尝试使用XOR而不是减法?请不要在注释中发布代码或格式化文本!编辑您的问题以包含所有相关信息。查看。请详细说明它的工作原理。抱歉,出现了一些错误,已修复并添加了解释;)我相信
std::numeric\u limits::digits
看起来更详细,但比
8
好。这怎么会比OP自己想出的更好呢?换句话说,这并不好。OP要求更快,而不是更一般。我不局限于8位,我在我的示例中也使用了
unsigned long long int
e已经在数组中找到了数字,他应该怎么做?@maxdev索引0000100处的值将是00000100,因此这将是搜索的结果。注意:对于64位,我们可以在3个测试中找到最高的非零字节(在
uint32\u t
上,然后是
uint16\u t
,最后是
uint8\u t
)。间隔减半。我喜欢它。:-)这怎么会比OP自己想出的更好呢?当然在最后一段中,对于64位数字,这只会多出一步?
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--;
}