1.原码

定义:十进制数据的二进制表现形式就是原码,原码最左边的一个数字就是符号位,0为正,1为负。

举例:56 $\to$ 0011 1000

  • 正数计算:

    5+2

    1
    2
    3
    4
     0 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
    4
     1 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
    4
      1 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
    4
     1 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
    4
     1 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 = 同上