&- 运算符的不同用法

Diffrent usage of &- operator

看下面的代码:

#include <stdio.h>

int main()
{
    int num, sum;
    scanf("%d", &num);
    sum = num - (num&-num);
    printf("%d", sum);
    return 0;
}

sum = num - (num& - num) returns给定数字的二进制格式的最后一个1的值。例如,如果 num 等于 6(110),它将给出没有最后一个 1 的值。在这种情况下,100 等于 4。 我的问题是 &- 是如何工作的,我们如何在八进制数字系统中做同样的事情?

这里有两个独立的运算符:按位与运算符 & 和一元取反运算符 -。所以有问题的行实际上是:

sum = num - (num & -num);

假设整数以二进制补码表示形式存储,取负值意味着反转所有位并加一。

num 为 6(二进制 00000110)的情况下,-num 为 -6 即 11111010。然后在这两个值之间执行按位与运算会得到二进制形式的 00000010,即2 十进制,所以 num - (num & -num) 是 6 - 2 即 4.

没有&-运算符。 num - (num&-num)num - (num & -num),其中 & 执行 num 的按位与及其取反 -num.

考虑一些二进制数字,例如 0011 0011 1100 11002(用于便于可视化的空格)。其负数为 −0011 0011 1100 11002。但是,我们通常使用补码表示负数,其中加上了 2 的幂。对于 16 位格式,我们添加 216,即 1 0000 0000 0000 00002。因此,为了表示 −0011 0011 1100 11002,我们使用 1 0000 0000 0000 00002 + −0011 0011 1100 1100 2 = 1100 1100 0011 01002.

从右边开始逐列观察这个减法中发生的事情:

  • 在最右边的列中,我们有 0−0,得到 0。
  • 下一列也有 0−0,得到 0。
  • 下一列有 0−1。这会产生 1,并从左侧的列中借位。
  • 下一列有 0−1−1(其中第二个 −1 是借位)。这会产生 0 和另一个借用。
  • 因为被减数(从中减去的数字)在初始 1 之前全为零,所以这个借位永远不会满足,所以它会在整个位中传播。

因此结果是:

  • 从右边开始,0 仍然是 0。
  • 第一个 1 保持为 1 但开始借用链。
  • 由于借位,该位左侧的所有位从 0 翻转到 1 或从 1 翻转到 0。

因此减数(被减去的数)和结果在第一个 1 左边的所有位都不同。并且它们在第一个 1 的右边都有 0。所以他们都设置的唯一位是第一个吗

因此,当使用补码时,num & -num的结果是num中设置的最低1位。

然后num - (num & -num)num中减去这个位,留下num,最低1位变为0。