上次
我在这篇文章中专门讲了带符号数据存储规则。今天再结合原码、反码和补码再来验证一下。
先从二进制规则说起:
原码:
数值的原码如果是正数,原码是它本身,负数第一位为1
比如 4,它的原码是0000 0100 ,-4的原码是1000 0100
反码:
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
4,它的反码是0000 0100 ,-4的反码是1111 1011
补码:
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
4,它的补码是0000 0100 ,-4的补码是1111 1100
结合上次文章中表格:
235 | -21 | 127+108 |
236 | -20 | 127+109 |
237 | -19 | 127+110 |
238 | -18 | 127+111 |
239 | -17 | 127+112 |
240 | -16 | 127+113 |
241 | -15 | 127+114 |
242 | -14 | 127+115 |
243 | -13 | 127+116 |
244 | -12 | 127+117 |
245 | -11 | 127+118 |
246 | -10 | 127+119 |
247 | -9 | 127+120 |
248 | -8 | 127+121 |
249 | -7 | 127+122 |
250 | -6 | 127+123 |
251 | -5 | 127+124 |
252 | -4 | 127+125 |
253 | -3 | 127+126 |
254 | -2 | 127+127 |
255 | -1 | 127+128 |
大家有没有惊奇的发现,-4的补码是1111 1100 ,这个数值表示252,对应的表格数值正好是252,证明我们前面的猜测完全正确。
结论:计算机内部对数值完全采用补码形式存储。
计算机巧妙地把符号位参与运算, 并且将减法变成了加法, 背后蕴含了化繁为简的巧妙的数学原理
有了补码知识,后面再使用golang的位运算就完全无问题了。
& 与 AND 两个都为1才为1
| 或 OR 两个有一个为1才为1
^ 异或 XOR 两个要相异
&^ 位清空 (AND NOT) a &^ b == a & (^b),把b按位取非之后和a做与
func main() {
fmt.Println(6 & 11)
fmt.Println(6 | 11)
fmt.Println(6 ^ 11)
fmt.Println(6 &^ 11)
}
6 =0000 0110
11=0000 1011
6 & 11=0000 0010 =2
6 | 11= 0000 1111 =15
6 ^ 11=0000 1101 =13
6 &^ 11=0000 0110 & (^0000 1011)= 0000 0110 & 1111 0100 =0000 0100 =4
用代码验证,完全一致。下面再用负数算一次:
package main
import (
"fmt"
)
func main() {
fmt.Println(-6 & 11)
fmt.Println(-6 | 11)
fmt.Println(-6 ^ 11)
fmt.Println(-6 &^ 11)
}
-6 =1111 1010
11 =0000 1011
-6 & 11=0000 1010 =10
-6 | 11= 1111 1011 =-1后 1111 1010取反1000 0101 也就是补码-5
-6 ^ 11=1111 0001 =-1后 1111 0000取反1000 1111 也就是补码-15
-6 &^ 11=1111 1010 & (^0000 1011)= 1111 1010 & 1111 0100 =1111 0000
-1后 1110 1111取反1001 0000 也就是补码-16
运行验证:
结果完全正确。golang作为新语言,基本原理和c语言都是一致的。