为什么在与 1 进行异或运算时取反值会改变结果?
Why does negating a value change the result when XORing it with 1?
我知道 XOR 的工作原理,
Console.WriteLine(1^1); // returns 0
结果
00000001
00000001
--------
00000000
但这 return 2 是怎么回事?
Console.WriteLine(-(-1^1)); // returns 2
这个表达式被编译器解释为:
-((-1)^1)
这是:
- ((11111111) XOR (00000001)) = -(11111110) = - (-2) = 2
要了解为什么编译器选择 -((-1)^1)
而不是 -(-(1^1))
,请查看有关 C# 运算符优先级的 this 文章。最相关的部分是一元 -
运算符(粗体:-( - 1^1) )比 XOR 运算符 ^
具有更高的优先级.因此否定发生在 XOR 之前,我们最终得到 -((-1)^1)
.
我在这里每个整数使用 8 位。通常你应该期望每个数字有 32 或 64 位,但在这种情况下它是无关紧要的;
要更好地理解为什么 11111111 是 -1,而 11111110 是 -2,请阅读有关二进制补码的更多信息 - https://en.wikipedia.org/wiki/Two%27s_complement。简而言之,您将除了最左边的所有位都视为 2 的连续幂。最左边的位被视为下一个幂,但为负数。
示例:
10001100 = 1 * (-(2^7)) + 0 * 2^6 + 0 * 2^5 + 0 * 2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
-1 存储为所有位都设置为 1 的值。如果我们继续使用您的 8 位示例,则 -1 将等于 11111111。因此 -1^1
给出以下内容:
11111111
00000001
--------
11111110
等于-2。当你用另一个减号反转它时,你得到 2.
负数以我们称之为two's complement的方式存储。如果你想在脑海中快速计算它,你可以翻转你的数字的正等价的所有位,然后加一。所以对于 -1:
1: 00000001
--------
11111110
+ 1
--------
-1: 11111111
解释为什么 -1 存储为 11111111。
如果你想更深入地了解二进制的补码,this question也可能对你有所帮助。
-1
是 11111111
(检查二进制补码)
当您使用 1
进行异或时,即 00000001
您有:
11111110
即 -2
(同样是二进制补码)
为了更好地理解二进制补码(数学可以很抽象),这是我记住的:
0
= 00...00
1
= 00...001
...
max - 1
= 011...110
max
= 011...11
min
= 100...00
min + 1
= 100...001
...
-1
= 11...11
显然,min
和 max
取决于您用来表示整数的位数
在二进制中使用二进制补码;
11111111^00000001=11111110
。
二进制补码 11111110
是十进制 -2
.
负数表示为binary complement,即
-x == ~x + 1
所以我们有
-(-1 ^ 1) ==
-(0b11111...1111 ^ 1) ==
-(0b11111...1110) ==
2
int 有 32 位。
-1 等于 1111 1111 1111 1111 1111 1111 1111 1111
1 等于 0000 0000 0000 0000 0000 0000 0000 0001
所以 -1 ^ 1 等于 1111 1111 1111 1111 1111 1111 1111 1110
等于 -2
所以 (-(-1^1)) = 2
查看整数和浮点数的位表示以获取更多信息。
我假设已签名 Int32
s.
-1 11111111111111111111111111111111 (two's complement)
1 00000000000000000000000000000001
-----------------------------------------
-1^1 11111111111111111111111111111110
-(-1^1) 00000000000000000000000000000010 --> 2
参见C# operator precedence and two's complement。
我知道 XOR 的工作原理,
Console.WriteLine(1^1); // returns 0
结果
00000001
00000001
--------
00000000
但这 return 2 是怎么回事?
Console.WriteLine(-(-1^1)); // returns 2
这个表达式被编译器解释为:
-((-1)^1)
这是: - ((11111111) XOR (00000001)) = -(11111110) = - (-2) = 2
要了解为什么编译器选择 -((-1)^1)
而不是 -(-(1^1))
,请查看有关 C# 运算符优先级的 this 文章。最相关的部分是一元 -
运算符(粗体:-( - 1^1) )比 XOR 运算符 ^
具有更高的优先级.因此否定发生在 XOR 之前,我们最终得到 -((-1)^1)
.
我在这里每个整数使用 8 位。通常你应该期望每个数字有 32 或 64 位,但在这种情况下它是无关紧要的;
要更好地理解为什么 11111111 是 -1,而 11111110 是 -2,请阅读有关二进制补码的更多信息 - https://en.wikipedia.org/wiki/Two%27s_complement。简而言之,您将除了最左边的所有位都视为 2 的连续幂。最左边的位被视为下一个幂,但为负数。
示例:
10001100 = 1 * (-(2^7)) + 0 * 2^6 + 0 * 2^5 + 0 * 2^4 + 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
-1 存储为所有位都设置为 1 的值。如果我们继续使用您的 8 位示例,则 -1 将等于 11111111。因此 -1^1
给出以下内容:
11111111
00000001
--------
11111110
等于-2。当你用另一个减号反转它时,你得到 2.
负数以我们称之为two's complement的方式存储。如果你想在脑海中快速计算它,你可以翻转你的数字的正等价的所有位,然后加一。所以对于 -1:
1: 00000001
--------
11111110
+ 1
--------
-1: 11111111
解释为什么 -1 存储为 11111111。
如果你想更深入地了解二进制的补码,this question也可能对你有所帮助。
-1
是 11111111
(检查二进制补码)
当您使用 1
进行异或时,即 00000001
您有:
11111110
即 -2
(同样是二进制补码)
为了更好地理解二进制补码(数学可以很抽象),这是我记住的:
0
= 00...00
1
= 00...001
...
max - 1
= 011...110
max
= 011...11
min
= 100...00
min + 1
= 100...001
...
-1
= 11...11
显然,min
和 max
取决于您用来表示整数的位数
在二进制中使用二进制补码;
11111111^00000001=11111110
。
二进制补码 11111110
是十进制 -2
.
负数表示为binary complement,即
-x == ~x + 1
所以我们有
-(-1 ^ 1) ==
-(0b11111...1111 ^ 1) ==
-(0b11111...1110) ==
2
int 有 32 位。
-1 等于 1111 1111 1111 1111 1111 1111 1111 1111
1 等于 0000 0000 0000 0000 0000 0000 0000 0001
所以 -1 ^ 1 等于 1111 1111 1111 1111 1111 1111 1111 1110
等于 -2
所以 (-(-1^1)) = 2
查看整数和浮点数的位表示以获取更多信息。
我假设已签名 Int32
s.
-1 11111111111111111111111111111111 (two's complement)
1 00000000000000000000000000000001
-----------------------------------------
-1^1 11111111111111111111111111111110
-(-1^1) 00000000000000000000000000000010 --> 2
参见C# operator precedence and two's complement。