C++ 我+=(i&;i)你认为呢?它是便携式的吗?

C++ 我+=(i&;i)你认为呢?它是便携式的吗?,c++,integer,bit-manipulation,C++,Integer,Bit Manipulation,设i为有符号整数类型。考虑 i += (i&-i); i -= (i&-i); 其中最初i>0 这些是干什么用的?是否有仅使用算术的等效代码 这是否取决于负整数的特定位表示 来源:在线编码拼图的setter代码(无任何解释/注释)。i&-i是获取整数i最低有效位(LSB)的最简单方法 您可以阅读更多内容。 A1:你可以阅读更多关于“数学等价物”的内容。 A2:如果负整数表示不是通常的标准形式(即奇怪的大整数),则i&-i可能不是LSB。表达式i&-i基于用于表示负整数。简单地说

i
为有符号整数类型。考虑

i += (i&-i);
i -= (i&-i);
其中最初
i>0

  • 这些是干什么用的?是否有仅使用算术的等效代码
  • 这是否取决于负整数的特定位表示

  • 来源:在线编码拼图的setter代码(无任何解释/注释)。

    i&-i
    是获取整数
    i
    最低有效位(LSB)的最简单方法
    您可以阅读更多内容。
    A1:你可以阅读更多关于“数学等价物”的内容。

    A2:如果负整数表示不是通常的标准形式(即奇怪的大整数),则
    i&-i
    可能不是LSB。

    表达式
    i&-i
    基于用于表示负整数。简单地说,它返回一个值
    k
    ,其中除
    i
    的最低有效非零位之外的每一位都设置为
    0
    ,但该特定位保持其自身的值。(即
    1

    只要您提供的表达式在用于表示负整数的系统中执行,它就可以移植。第二个问题的答案是,表达式依赖于负整数的表示

    为了回答第一个问题,由于算术表达式依赖于数据类型及其表示形式,因此我认为没有一个单独的算术表达式可以等同于表达式
    I&-I
    。本质上,下面的代码在功能上等同于该表达式。(假设
    i
    int
    类型)请注意,我必须使用循环来生成相同的功能,而不仅仅是算术

    int tmp = 0, k = 0;
    while(tmp < 32)
    {
        if(i & (1 << tmp))
        {
            k = i & (1 << tmp);
            break;
        }
        tmp++;
    }
    i += k;
    
    inttmp=0,k=0;
    而(tmp<32)
    {
    
    如果(i&(1在2的补码结构上,使用4位有符号整数:

    |  i |  bin | comp | -i | i&-i | dec |
    +----+------+------+----+------+-----+
    |  0 | 0000 | 0000 | -0 | 0000 |   0 |
    |  1 | 0001 | 1111 | -1 | 0001 |   1 |
    |  2 | 0010 | 1110 | -2 | 0010 |   2 |
    |  3 | 0011 | 1101 | -3 | 0001 |   1 |
    |  4 | 0100 | 1100 | -4 | 0100 |   4 |
    |  5 | 0101 | 1011 | -5 | 0001 |   1 |
    |  6 | 0110 | 1010 | -6 | 0010 |   2 |
    |  7 | 0111 | 1001 | -7 | 0001 |   1 |
    | -8 | 1000 | 1000 | -8 | 1000 |   8 |
    | -7 | 1001 | 0111 |  7 | 0001 |   1 |
    | -6 | 1010 | 0110 |  6 | 0010 |   2 |
    | -5 | 1011 | 0101 |  5 | 0001 |   1 |
    | -4 | 1100 | 0100 |  4 | 0100 |   4 |
    | -3 | 1101 | 0011 |  3 | 0001 |   1 |
    | -2 | 1110 | 0010 |  2 | 0010 |   2 |
    | -1 | 1111 | 0001 |  1 | 0001 |   1 |
    
    备注:

  • 您可以推测
    i&-i
    只有一个位集(它是2的幂),并且它与
    i
    的最低有效位集相匹配
  • i+(i&-i)
    有一个有趣的特性,就是更接近2的下一次幂
  • i+=(i&-i)
    设置
    i
    的最低有效未设置位
  • 因此,做
    i+=(i&-i);
    最终会让你跳到下一个二次幂:

    | i | i&-i | sum |     | i | i&-i | sum |
    +---+------+-----+     +---+------+-----+
    | 1 |    1 |   2 |     | 5 |    1 |   6 |
    | 2 |    2 |   4 |     | 6 |    2 |  -8 |
    | 4 |    4 |  -8 |     |-8 |   -8 |  UB |
    |-8 |   -8 |  UB |
    
    | i | i&-i | sum |     | i | i&-i | sum |
    +---+------+-----+     +---+------+-----+
    | 3 |    1 |   4 |     | 7 |    1 |  -8 |
    | 4 |    4 |  -8 |     |-8 |   -8 |  UB |
    |-8 |   -8 |  UB |
    

    UB:有符号整数的溢出表现出未定义的行为。

    以下是我根据其他答案所做的研究。位操作

    i -= (i&-i);   // strips off the LSB (least-significant bit)
    i += (i&-i);   // adds the LSB
    
    主要用于遍历a。特别是,
    i&-i
    给出LSB,如果有符号整数通过表示。正如他最初的建议中所述,这不适用于其他有符号整数表示。但是

    i &= i-1;      // strips off the LSB
    
    is(它也可以与和表示一起使用),并且少了一个操作


    然而,似乎没有简单的便携式替代品来添加LSB。

    最简单的方法是从数学等价性的角度来考虑它:

    -i == (~i + 1)
    
    因此
    -i
    将值的位反转,然后添加
    1
    。其意义在于
    -i
    的所有低位
    0
    位通过
    -i
    操作转换为
    1
    s,因此向值添加
    1
    会导致所有低位
    1
    位翻转为
    0
    向上移动
    1
    ,直到它落在
    0
    位,刚好与
    i
    中最低的
    1
    位处于同一位置

    下面是数字6(二进制0110)的示例:

    在意识到位中的模式之前,您可能需要手动执行每个操作几次

    这里还有两个例子:

    i = 1000
    ~i == 0111
    (~i + 1) == 1000
    i & (~i + 1) == 1000
    
    i = 1100
    ~i == 0011
    (~i + 1) == 0100
    i & (~i + 1) == 0100
    
    查看
    +1
    如何导致一种“位级联”,将其带到第一个打开的
    0


    因此,如果
    (i&-i)
    是提取最低
    1
    位的一种方法,那么
    i+=(i&-i)
    i-=(i&-i)
    的用例都是尝试对值的最低1位进行加减

    将值的最低1位从其自身中减去可将该位归零

    将值的最低1位添加到其本身似乎没有任何特殊用途,它只是按照tin上的说明执行



    它应该可以在任何使用2的补码的系统上移植。

    如果
    i
    具有无符号类型,则表达式可以完全移植并定义良好

    如果
    i
    有符号类型,它就不可移植,因为
    &
    是根据表示定义的,而一元
    -
    +=
    -=
    是根据值定义的。但是,如果

    在无符号情况下(以及两位补码情况下),很容易确认
    i&-i
    是二的幂(只有一位非零),并且与
    i
    的最低位(也是
    -i
    的最低位)具有相同的值。因此:

    • i-=i&-i;
      清除
      i
      的最低设置位
    • i+=i&-i;
      增加
      i
      的最低设定位(清除,但带进位到较高的位)

    对于无符号类型,两个表达式都不会溢出。对于有符号类型,当
    i
    最初具有类型的最小值时,
    i-=i&-i
    溢出,当
    i
    最初具有类型的最大值时,
    i+=i&-i
    溢出,
    i&-i
    i
    的连续值形成一个分形图案,例如:
    0 1 2 1 4 1 2 1 8 1 4 1 1 1 2 1 16 2 1 4…
    希望这篇文章能帮到你。这篇文章解释得很好。@Walter,它对我很有用
    i = 1000
    ~i == 0111
    (~i + 1) == 1000
    i & (~i + 1) == 1000
    
    i = 1100
    ~i == 0011
    (~i + 1) == 0100
    i & (~i + 1) == 0100