原码
- 为什么要用原码?
计算机的存储是以二进制为基础的,因此正负号难以表示,所以,在二进制表示的基础上,选取最高位作为符号位; - 原码带来了什么问题?
1. 出现了+0(0000 0000)
和-0(1000 0000)
,明显不符合常理
2. 关于负数和正数的计算是完全错误的,例如:
-3(1000 0011)+ 1(0000 0001) = -4(1000 0100)
很明显,问题出在计算时符号位是无法被正确体现的,严格来说,遇到减法时,都会出现这种问题,减法被表现成了加法。
反码
- 为什么要用反码?
一定程度上解决了正数与负数的运算问题。
如何解决的?
在原码的基础上- 正数保持不变;
- 负数的符号位不变,但其他的位按位取反。(
1000 0001
变为1111 1110
)
原理可以用钟表的一圈来解释:我们知道按上面的构造方法,在负数情况下,原码加上补码一定会得到1111 1111
(此处仅以8位举例),抛开符号位,仅讨论其他位的数值大小,我们会发现,如果补码加上1,为了维持原补相加的固定值,那么原码就会减去一个1。因此通过补码的加法操作,我们实现了原码的减法。
- 补码带来了什么问题?
1.+0(0000 0000)
和-0(1000 0000)
的问题依然没有解决,带来了跨越零点的问题:
-3(1000 0011)+ 4(0000 0100)
-3转为反码:1111 1100
相加得到: 0000 0000
原因:因为存在+0与-0,所以跨越0点时,一定会比原来的值小1.
补码
- 为什么要用补码?
解决了+0与-0的问题。
如何解决的?
在反码的基础上
正数不变,负数再加一,因此-0(1000 0000)
取反加1得到+0(0000 0000)
,实现了统一。
最后出现的细节,为什么大多数的有符号数据类型负数范围比正数范围多1?
以8位举例1111 1111
的补码为1000 0001
而1000 0000
对应的原码和补码其实都不存在,但计算机是以补码进行存储的,因此,-128是合法的。