原码、反码、补码
原码、补码、反码是计算机中最基础的知识,但一直没熟练掌握,经常忘,这里做个记录。
原码
最高位是符号位,其余位用来表示这个数的绝对值。
例如 在32位数中:
+1的原码是0000,0001;
+5的原码是0000,0101;
-17的原码是1001,0001;
如果这个世界只有正数,那么我们只需要原码就够了,但还有负数…
例如:
-3(1000,0011)+3(0000,0011)= -6(1000,0110)
因此,原码会带来两个问题
- 负数或减法运算会出现错误
- 0有两种表示方式 +0(0000,0000) 和 -0(1000,0000)
反码
正数反码就是原码,负数符号位不变,其余位取反
我们尝试用反码来计算减法:
-3(1111,1100)+3(0000,0011)= -0(1111,1111)
乍一看计算结果好像是正确的,那我们再试两个:
4(0000,0100)-9(1111,0110)= -5(1111,1010)
-28(1110,0011)+8(0000,1000)= -20(1110,1011)
也是正确的,再试两个:
4(0000,0100)-3(1111,1100)= 0(1,0000,0000)舍去高位变成0
17(0001,0001)-6(1111,1001)= 10(1,0000,1010)舍去高位变成10
在这两个例子都是大正数加上一个小负数,都出现了溢出,舍去最高位后都不是正确的答案。
反码也还是存在一些问题
- 部分运算还是不正确的,绝对值相同的正数和负数相加是正确的
- 0还是有两种表示方式,+0(0000,0000) 和 -0(1111,1111)
补码
正数的补码就是原码,负数的补码是反码+1
之前说过,反码的”0“是有两种表示方式,+0(0000,0000) 和 -0(1111,1111)。
但在补码中,”+0“的补码还是”0000,0000“,计算”-0“的补码,反码+1,变成了”1,0000,0000”,舍去最高位也变成了”0000,0000” 。
因此补码中的”0“只有一种表达方式—— “0000,0000”
同样,不会出现计算错误的情况:
4(0000,0100)-3(1111,1101)= 1(1,0000,0001)舍去高位变成1
17(0001,0001)-6(1111,1010)= 11(1,0000,1011)舍去高位变成11
反码和补码都是为了解决负数问题而出现的,所以正数的反码和补码都是原码。####
为什么负数总比正数多一个?####
理论上,8位数,用补码表示的范围是 1111,1111 ~ 0111,111 ,即 -127,-126,-125 ….-1,-2,-0,+0,1,2 …. 126,127 去掉”-0” 就可以了。由于在补码中,没有反码可以通过+1变成”1000,0000”,所以人为规定”1000,0000”为”-128”,这也是为什么负数比正数多一个的原因。