【c++笔记】原码补码和反码
1.原码
定义:十进制数据的二进制表现形式就是原码,原码最左边的一个数字就是符号位,0为正,1为负。
举例:56 $\to$ 0011 1000
正数计算:
5+2
1
2
3
40 0 0 0 0 1 0 1
+ 0 0 1 0
-----------------
0 0 0 0 0 1 1 1负数计算
负数结果不正确,例如 -56-1原本应该是-57(1 0 1 1 1 0 0 1),但实际结果是-55(1 0 1 1 0 1 1 1),为了解决该问题,引入反码
1
2
3
41 0 1 1 1 0 0 0
- 1
-----------------
1 0 1 1 0 1 1 1
2.反码
定义:正数的反码是其本身(等于原码),负数的反码是符号位保持不变,其余位取反。反码的存在是为了正确计算负数,因为原码不能用于计算负数。
负数计算:
计算-56 - 1
-56 的原码是 1 0 1 1 1 0 0 0 ,如果转成反码(符号位不变,其他位取反),反码是 1 1 0 0 0 1 1 1
1
2
3
41 1 0 0 0 1 1 1
- 1
-----------------
1 1 0 0 0 1 1 0-57 的原码是 1 0 1 1 1 0 0 1,转成反码刚好是 1 1 0 0 0 1 1 0,等于算出的值
跨零计算
计算-3 + 5,-3 的原码是 1 0 0 0 0 0 1 1,转成反码的话就是 1 1 1 1 1 1 0 0,结果错误
1
2
3
41 1 1 1 1 1 0 0
+ 0 1 0 1
-----------------
0 0 0 0 0 0 0 1
3.补码
定义:正数的补码是其本身,负数的补码等于其反码 +1,也就是除了符号位之外的部分取反再加1。
因为反码不能解决负数跨零(类似于 -6 + 7)的问题,所以补码出现了。
跨零计算
-3 的原码是 1 0 0 0 0 0 1 1,转成反码的话就是 1 1 1 1 1 1 0 0,再转成补码就是 1 1 1 1 1 1 0 1
1
2
3
41 1 1 1 1 1 0 1
+ 0 1 0 1
-----------------
0 0 0 0 0 0 1 0把这个数转成十进制刚好等于2,结果正确
4.三种编码总结
在计算机当中都是使用补码来进行计算和存储的。补码很好的解决了反码负数不能跨零计算的弊端。
5.计算机中数据的存储
假设某台机器的int和unsigned int都占用4个字节,即32位。
5.1存储int型
在存储int型数据时,按照原始数据的补码存储。由于最高位是符号位,因此int所能表示数据的范围应为 -2^31 ~ (2^31)-1 。
例如:
存储int型1时,记录的为:0000 0000 0000 0000 0000 0000 0000 0001(补码)
存储int型-1时,记录的为:1111 1111 1111 1111 1111 1111 1111 1111(补码)
为什么是是2^31 不是 2^32?
最大存储2^32 次方,但32位的第一位是符号位。所以是2^31次方为什么是是 2^31-1 ,不是2^31?
最后的减一操作是因为把0也算在正数里,这样负数和正数数量刚好各占一半
5.2存储unsigned int型
在存储unsigned int型数据时,按照原始数据的补码存储,unsigned所能表示的范围为 0 ~ 2^32-1。因为无符号数不可能是负数,所以其补码也就是其原码。例如:
存储unsigned int型1时,记录的为:0000 0000 0000 0000 0000 0000 0000 0001
6. int型转换为unsigned int型
int型转换为unsigned int型其实就是把int型的31位和表示符号的最高位,一起看作是unsigned int型的32位一并读取,例如:
int型1:0000 0000 0000 0000 0000 0000 0000 0001,按unsigned的32位读法仍然为1
int型-1:1111 1111 1111 1111 1111 1111 1111 1111,按unsigned的32位读法为 2^32-1 = 4294967295
正数转换为unsigned时,数值与原来相等;负数转换为unsigned时,数值会发生变化。
c++ primer练习2.3:
unsigned int u = 10, u2 = 42;
u2 - u = 32
u - u2 = 10+(-42)= 0000 0000 0000 0000 0000 0000 0000 1010(补) + 1111 1111 1111 1111 1111 1111 1101 0110(补) = 1111 1111 1111 1111 1111 1111 1110 0000 = 4294967264
int i = 10, i2 = 42;
i2 - i = 32
i - i2 = -32
i - u (int 变成 unsigned int)= 0000 0000 0000 0000 0000 0000 0000 1010(补) + 1111 1111 1111 1111 1111 1111 1111 0110 = 0001 0000 0000 0000 0000 0000 0000 0000 = 4294967296(溢出)= 0
u - i = 同上

