【计算机组成原理】原码、反码、补码
前⾔
因为CPU运算器中只有加法器,所有要把减法转换加法来运算,同时也是为了节约成本。负数二进制补码运算法则
我们知道,根据运算法则减去⼀个正数等于加上⼀个负数,即:1-1 = 1 + (-1) = 0 ,所以机器可以只有加法⽽没有减法,这样计算机运算的设计就更简单了。
于是⼈们想出了将符号位也参与运算的⽅法。
对于有符号数,符号的“正”“负”机器⽆法识别,因为正负刚好是截然两种状态,⽤”0“表⽰”正“,⽤”1“表⽰”负“,这样符号就被数字化了,规定将它们放在有效数字前⾯,组成有符号数。
原码
⼈们开始探索 将符号位参与运算,并且只保留加法的⽅法。⾸先来看原码:
⼀个正数,按照绝对值⼤⼩转换成的⼆进制数;⼀个负数按照绝对值⼤⼩转换成的⼆进制数,然后最⾼位补1,称为原码。
⽐如
00000000 00000000 00000000 00000101 是 5的 原码。
10000000 00000000 00000000 00000101 是-5的 原码。
计算⼗进制的表达式:1-1=0
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [1000 0010]原 = -2
1-1
=1+(-1)
=[00000001]原+[10000001]原
=[10000010]原
=-2
如果⽤原码表⽰,让符号位也参与计算,显然对于减法来说,结果是不正确的。这也就是为何计算机内部不使⽤原码表⽰⼀个数。
备注:
⽐如byte类型,⽤2^8来表⽰⽆符号整数的话,是0 - 255了;
如果有符号, 最⾼位表⽰符号,0为正,1为负,那么,正常的理解就是 -127 ⾄ +127 了,这就是原码了。
值得⼀提的是,原码的弱点,有2个0,即+0和-0(0000 0000和1000 0000);
还有就是,进⾏异号相加或同号相减时,⽐较⿇烦,先要判断2个数的绝对值⼤⼩,然后进⾏加减操作,最后运算结果的符号还要与⼤的符号相同。
于是,反码产⽣了。
反码
为了解决原码做减法的问题,出现了反码:
正数的反码与原码相同。
负数的反码为对该数的原码 除符号位外各位取反[每⼀位取反(除符号位)]。
取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)
⽐如:
正数 5 00000000 00000000 00000000 00000101 的反码
还是— 00000000 00000000 00000000 00000101;
负数 -510000000 00000000 00000000 00000101 的反码
则是— 11111111 11111111 11111111 11111010;
反码是相互的,所以也可称:10000000 00000000 00000000 00000101和 11111111 11111111 11111111 11111010互为反码。
计算⼗进制的表达式: 1-1=0
1-1
=1+(-1)
=[00000001]原+[10000001]原
=[00000001]反+[11111110]反
=[11111111]反
=[10000000]原
=-0
发现⽤反码计算减法,结果的真值部分是正确的。⽽唯⼀的问题其实就出现在0这个特殊的数值上。
虽然⼈们理解上+0和-0是⼀样的,但是0带符号是没有任何意义的,⽽且会有[0000 0000]原和[1000 0000]原两个编码表⽰0。
补码
于是补码的出现, 解决了0的符号以及两个编码的问题:
正数的补码与原码相同;
负数的补码为对该数的原码除符号位外各位取反,然后在最后⼀位加1;
⽽使⽤补码表⽰时⼜可以多保存⼀个最⼩值。.
⽐如:
-5的原码是10000000 00000000 00000000 00000101
反码是:11111111 11111111 11111111 11111010。
那么,补码为:
11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011
计算:
1-1
=1+(-1)
=[00000001]原+[10000001]原
=[00000001]补+[11111111]补
=[00000000]补=[00000000]原
这样0⽤[0000 0000]表⽰, ⽽以前出现问题的-0则不存在了,⽽且可以⽤[1000 0000]表⽰-128:
(-1)+(-127)
=[10000001]原+[11111111]原
=[11111111]补+[10000001]补
=[10000000]补
-1 - 127的结果应该是-128,在⽤补码运算的结果中,[1000 0000]补 就是-128。
但是注意,因为实际上是使⽤以前的-0的补码来表⽰-128,所以 -128并没有原码和反码表⽰。(对-128的补码表⽰[1000 0000]补算出来的原码是[0000 0000]原,这是不正确的)
使⽤补码,不仅仅修复了0的符号以及存在两个编码的问题,⽽且还能够多表⽰⼀个最低数。这就是为什么8位⼆进制,使⽤原码或反码表⽰的范围为[-127, +127],⽽使⽤补码表⽰的范围为[-128, 127]。
因为机器使⽤补码,所以对于编程中常⽤到的32位int类型,可以表⽰范围是: [-2^31, 2^31-1] 因为第⼀位表⽰的是符号位。
从补码求原码的⽅法跟原码求补码是⼀样的取反再加1 ,也可以通过完全逆运算来做(除了-128也就是[1000 0000]补 ),先减⼀,再取反。补码的补码=原码
针对负数⽽⾔,
任意8位⼆进制负数:
原码+反码=1111 1111
补码=反码+1
补码+补码的反码=1111 1111
补码的补码=补码的反码+1
所以 反码+1+补码的补码-1=1111 1111
所以 反码+补码的补码=1111 1111
所以 补码的补码=1111 1111-反码=原码
总结
三种机械数的最⾼位均为符号位。
符号位和数值位可以⽤.或者,隔开。
当真值为正时,原码、补码、反码的表现形式均相同,符号位为0,数值部分和真值相同。
当真值为负时,原码、补码、反码的表现形式均相同,符号位为1,数值部分,补码是原码的”求反加1’,反码是原码的“每位求反”。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论