大家可能已经了解到计算机内部信息通过1与0存储,如果计算机想存储一个2,那么在计算机内部存储的是10, 如果存储的是4,那么计算机内部存储的是1000,如果大家理解到这里,那只能说理解了一半。为什么说是一半呢,因为这个只是一个十进制正整数转换为二进制的一个结果,但是实际上,还有负数,浮点数、定点小数的存储,他们的存储并不是简单的直接转换为二进制保存。
这就是二进制的原码、补码、反码
二进制原码
要了解二进制原码,首先从他的符号位开始
符号位
在计算机中参与运算的数分为有符号数与无符号数
- 无符号的数,也就是他的二进制信息里面不包含符号位,所以无符号数只能表示非负数
- 有符号位的数,二进制的左边第一位为符号位,当这一位为0表示正数,为1表示负数
想一下,十进制的2与-2的二进制表示应该怎么样?
如果用8位二进制表示
2的二进制 - 0000 0010, 最左侧为0,表示这是一个正数
-2的二进制 - 1000 0010, 最左侧为1, 表示这是一个负数
那么这里的 0000 0010就称为十进制2的原码,同理 1000 0010就是十进制的-2的原码
原码的问题
根据数学运算规则,正数+他的负数应该等于0,比如2 + (-2) = 0, 那么我们来观察一下原码的运算:
0000 0010 + 1000 0010 = 1000 0100 对应十进制的 -4 ,这个结果显然不对
因此我们不能直接的在计算机中使用负数的原码来保存负数
二进制补码
既然原码不符合正负相加为0的运算法则,那么我们可以考虑一下,负数应该怎么样才能为0
还是以2的八位二进制为例
0的八位二进制为 0000 0000
那么 0000 0010 + ? = 0000 0000 ,?应该是个什么数。
如果我们直接考虑结果为 0000 0000,可能不好推算,但是如果假设可以添加1位,也就是 1 0000 0000, 能不能想到呢?
显然,可以考虑到 0000 0010 + 1111 1110 = 1 0000 0000, 最左侧的1由于超出了八位会被计算机丢弃,所以就可以得到0000 0000。
这里的 1111 1110就是 0000 0010的补码,是-2在计算机中的二进制存储
对于正数2,他的原码就是他的补码
二进制反码
正数的补码就是他的原码,这个比较好计算,那么负数的补码如何通过他的原码来计算出来?
这就需要用到反码
计算反码
反码就是将原来的二进制除符号位以外的位进行逐位取反
分析一下:
1000 0010 求他的反码
1111 1101 这个就是他的反码
这里大家考虑一下, 2的原码 + (-2的反码)的结果是什么?
0000 0010 + 1111 1101 = 1111 1111
可以看到反码相加的结果比目标0少了一个1,所以接下来就是很简单的结果
根据反码计算补码
只要在反码的基础上加上1,就得到了负数的补码
1111 1101 + 1 = 1111 1110
这样就计算出了他的补码
注意事项
在计算机中,无论正负数都是以补码形式存储,正数的补码就是他的原码,那么在进行位计算的时候,我们一定要记得使用补码进行位计算
以下面的运算为例:
# ~按位取反
print(~10)
# -11
print(~-10)
# 9
大家可以手工推算一下,是不是与运行结果一致
~10的计算过程:
以8位二进制表示, 按位取反是对补码取反
第一步:
10的补码是 0000 1010第二步:
由0000 1010按位取反可以得到:
1111 0101, 这得到是一个补码,从第一位可以看出是一个负数,所以需要根据这个补码计算他的原码,要计算原码首先计算他的反码第三步:
计算反码
1111 0101 - 1 = 1111 0100 这就是他的反码(反码+1 = 补码)第四步:
由反码计算他的原码:1111 0100 -> 1000 1011 ,符号位保持不变,其他位取反,所以最后得到的是-11
~-10的计算过程:
第一步:
-10的原码是:
1000 1010, 这是负数的原码,~取反运算是在负数的补码上计算的,所以需要先计算出他的补码
第二步:
1000 1010 的补码是 1111 0110
第三步:
对 1111 0110进行取反得到 : 0000 1001,第一位是0,是一个正数,所以这个码就是原码,可以知道结果是9
讨论区