【发布时间】:2022-04-12 15:19:38
【问题描述】:
fmt.Println(^1)
为什么会打印-2?
标签: go bitwise-operators twos-complement
fmt.Println(^1)
为什么会打印-2?
标签: go bitwise-operators twos-complement
^ 运算符是按位补码运算符。 Spec: Arithmetic operators:
对于整数操作数,一元运算符
+、-和^定义如下:+x is 0 + x -x negation is 0 - x ^x bitwise complement is m ^ x with m = "all bits set to 1" for unsigned x and m = -1 for signed x所以二进制中的
1是一个单一的 1 位,前面是全零:0000000000000000000000000000000000000000000000000000000000000001所以按位补码是一个 0 位,前面有一个全 1:
1111111111111111111111111111111111111111111111111111111111111110
^1是一个无类型的常量表达式。当它被传递给一个函数时,它必须被转换为一个类型。由于1是无类型整数constant,因此将使用其默认类型int。 Go 中的int使用2's complement 表示,其中负数以1开头。完整的数字是-1,小一的数字(二进制)是-2等。上面的位模式是
-2的 2 的补码表示。要打印位模式和类型,请使用以下代码:
fmt.Println(^1) fmt.Printf("%T\n", ^1) fmt.Printf("%064b\n", 1) i := ^1 fmt.Printf("%064b\n", uint(i))它输出(在Go Playground 上尝试):
-2 int 0000000000000000000000000000000000000000000000000000000000000001 1111111111111111111111111111111111111111111111111111111111111110
【讨论】:
好的,这与我们在计算中使用符号的方式有关。
对于一个 1 字节的数字,你可以得到
| D | B |
|---|---|
| -8 | 1000 |
| -7 | 1001 |
| -6 | 1010 |
| -5 | 1011 |
| -4 | 1100 |
| -3 | 1101 |
| -2 | 1110 |
| -1 | 1111 |
| 0 | 0000 |
| 1 | 0001 |
| 2 | 0010 |
| 3 | 0011 |
| 4 | 0100 |
| 5 | 0101 |
| 6 | 0110 |
| 7 | 0111 |
您可以在此处看到 1 等于 0001(没有任何变化),但 -1 等于 1111。^ 运算符执行按位异或运算。所以:
0001
1111 xor
-------
1110 -> That is actually -2.
这一切都是因为two complement 的约定,我们用它来进行负数计算。当然,这可以外推到更长的二进制数。
您可以通过使用 windows 计算器进行异或位计算来测试这一点。
【讨论】: