【问题标题】:Setting all bits before first '1'在第一个“1”之前设置所有位
【发布时间】:2012-09-13 17:25:48
【问题描述】:

假设一个 32 位无符号整数(可推广到任何大小的答案当然更好)。

可以假设这个整数是 2 的幂,所以只设置了一位。 我想设置整数中的所有位,除了那些低于设置位的位。因此(为简洁起见,使用 8 位整数)00001000 将变为 11111000

这当然可以通过找到一个设置位然后遍历更高位并设置它们来完成。假设highest_set返回最高设置位的位置:

uint32_t f(uint32_t x)
{
  int n = highest_set(x);
  for (int i = 31; i != n; --i) {
      x |= 1 << i;
  }
  return x;
}

f 的运行时间确实取决于x 的值,我觉得有一个更聪明的方法来做到这一点。

【问题讨论】:

    标签: binary integer bit-manipulation


    【解决方案1】:

    从概念上讲,一个简单的做法是获取x-1,然后与0xffffffff 进行异或运算。将其写为~(x-1) 就像 harold 在下面的 cmets 中所做的那样,将处理不同大小的整数,而无需更改您的异或运算。

    【讨论】:

    • 您提到的~(x - 1) 解决方案可能在任何现代设备上都更快。代码也更少。
    • @harold 同意。我刚刚删除了有关查找表的部分,因为在大多数情况下它感觉更混乱,没有真正的优势。
    【解决方案2】:

    右移对数(值), 或位掩码为 1, 左移日志(值)。 这应该是一个通用解决方案,对于任何输入都具有相同的运行时间,但不能保证。

    【讨论】:

      【解决方案3】:

      你只需要取两者的补码

      x = -x;
      

      无论 x 是有符号还是无符号,它都有效

      为什么?因为您所做的实际上是一种将数字转换为 2 的补码的快速方法

      手动将二进制数转换为二进制补码的捷径是从最低有效位开始 (LSB),然后复制所有零(从LSB开始朝向最高有效位)直到达到第一个 1;然后复制那个 1,并翻转所有剩余的位

      https://en.wikipedia.org/wiki/Two%27s_complement#Working_from_LSB_towards_MSB

      您只有 一个位集,因此当您复制所有零位并反转剩余的零位时,您会得到其 2 的补码。您可以在示例中看到它:00001000 = 8, 11111000 = -8。其他一些例子:

      00010000 = 16, 11110000 = -16
      00100000 = 32, 11100000 = -32
      01000000 = 64, 11000000 = -64
      

      如果 x 是 signed 类型,那么它很容易理解。在 unsigned 类型的情况下,显然没有负值,因此它基于how the C standard defined unsigned operations

      涉及无符号操作数的计算永远不会溢出,因为无法由生成的无符号整数类型表示的结果会以比结果类型可以表示的最大值大一的数字为模减少。

      这只是another definition of 2's complement,因为比结果类型可以表示的最大值大一个(即在这种情况下为UINT<b><i>N</i></b>_MAX + 1)是2N。对无符号值求反总是会在 C 中产生其二进制补码,即使有符号类型是符号大小或一个补码

      当然,如果您想输入更多内容,您也可以将其转换为签名类型x = -(int32_t)x;。你还有另一个解决方案

      x = ~x + 1; // by 2's complement definition
      

      一个易于理解的解决方案

      while (!(x & 0x80000000))
          x |= x << 1;
      

      此代码不需要像上面的许多解决方案那样一直循环 32 次​​p>

      【讨论】:

        【解决方案4】:
        uint32_t f(uint32_t x)
        {
          bool bitset=false; //C++
          for (int i =0; i<sizeof(int); i++) {
             if(bitset) //After the first 1
                {  x |= 1 << i; } 
              else
                {
                  if(x&(1<<i))
                    bitset=true; //if 1 found then the flag is raised
                }
        
          }
          return x;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-19
          相关资源
          最近更新 更多