原码、反码、补码——怎样理解它们在数据存储与运算中的作用?!

记得大一时C语言课一开始,老师便介绍了原码、反码、补码以及怎样进行运算,其实也很简单——
正数和0的原码、反码、补码是其本身,
负数的反码由原码按位取反得到,补码则取反后再加1即可,
此外首位作为符号位,0为正,1为负,取反过程中符号位保持不变
……
也无非是这些罢了。
但是为什么要有这些码存在呢?
数据又为什么要以补码形式来存储呢?
一个字节为什么只能存储-128~127?
这些疑惑一直堆积在我的心里,于是本文就是近几天我的一点研究成果,这些码都是基于实际存储和运算的需要而诞生的,如果你有相似的疑惑,相信本文能够解决~

数据存储的单位
要了解数据是怎样被存储的,我们首先要了解的是数据容量的一些单位及相互换算关系,从小到大如下:
8bit=1Byte
1024Byte=1KB
1024KB=1MB
1024MB=1GB
1024GB=1TB
1024TB=1PB
1024PB=1EB
更大的单位还有,在此不必列举。
其中,bit(位)是最小单位,每一个位可以用来表示0或1,
计算机中一切数据都是0和1组成的序列

接下来,抛开你之前学过的零碎的关于原码、反码、补码的相关知识,让我们一起来考虑整型如何存储:
假设我们用8个位来存储整数(全文以8位为例),例如存储正整数1,只需存0000 0001即可,那么它的数据范围即0000 0000~1111 1111(1~255),最大255。

负数如何存储?
但负数怎么存储?由于计算机这个铁憨憨每位只能表示0或者1两种状态,因此我们必须设立一个符号位,存储时将最高位用0表示正数,1表示负数,其他位则用来存储这个数的绝对值。(当然,1为负,0为正也可以,但我们姑且这样设定)

这样一来,正整数的范围为0000 0001~0111 1111(1~127),负整数的范围为1000 0001~1111 1111(-1~-127),此外还有0000 0000(+0),1000 0000(-0)。

将最高位作为符号位后,单是存储整数没问题了,
那让我们来尝试以下计算(大家跟着一起算~),
3+5=0000 0011+0000 0101=0000 1000=8,结果正确。
3-5=3+(-5)=0000 0011+1000 0101=1000 1000=-8 结果错误
问题在哪?
在计算时直接将3和5数据位的值相加,符号位不变,最终结果也就是-8
怎样解决这个问题?
这里我们先给出一个方案:
将-5除了符号位以外所有位取反(1变0 0变1),再与3相加,将得到的结果再次取反。
即3-5=3+(-5)=0000 0011+1000 0101(原)=0000 0011+1111 1010(反)=1111 1101(反)=1000 0010(原)=-2
为什么这样运算能得到正确结果?
-5的数据位原来是000 0101 取反后变为111 1010,实际上是变成了127-5=122
3-5就变成了3+122=125,对125再次取反,变成127-125=2,得到正确结果。
由于111 1111是127,而取反操作 保证了相应数据位之和必为1,因此,取反前后的数据和为127,取反后的值也就是127减去取反前的值。
前后的运算过程可以写成这样一个式子:
3-5=3+(-5)=-[127-(3+127-5)]=-2
在这里,出于计算3-5的需要,我们引入了反码的概念——除了符号位之外全部取反后的码。

当3+5和3-5都解决了,我们不妨再尝试一下5-3,大家可以手算一下,发现当5-3时,由于5+127-3大于127,此时数据会进位到符号位,符号位变成0并进位,由于只用8位数字存储,最前面的1无效,最终结果为0000 0001,显然,这样进行取反结果已经不正确了。
我们观察这里的数字,是实际结果减1。因此我们选择当存储的数字为负数时,对它进行取反再加1,于是乎,5-3=0000 0101+1000 0011(原码)=0000 0101+1111 1101=1 0000 0002 这里的1超出8位无效,因此结果就是2
在这里,出于计算5-3的需要,我们引入了补码的概念——反码加1的码。

这样的话,在计算机中,正数仍然以原码形式存储,只不过最高位作为符号位,负数则以反码加1——即补码的形式存储,当有负数参与运算时,只需要将结果从补码形式转化为原码即可得到结果。

知道了数字以补码形式存储,我们可以得到这样一个补码和数字相对应的表:
在这里插入图片描述
在这张图片中淡黄色的那一行是我要重点说明的:
补码从0000 0000~1111 1111,我们容易推算出,除了1000 0000,其他都有相对应的原码。但是1000 0000,由于减1时要向高位借位,但这里数据位全为0,符号位又不能借位,推断不出相应的原码。
那么这个位置是否就没有对应的原码呢?
表示0我们只需要有0000 0000即可,并不需要1000 0000也表示0,事实上,我们可以将它作为一个特殊的补码,来存储-128,从而使得与1000 0001的-127连贯起来,也让补码不至于中间断层。
在这里插入图片描述
到这里,我们能自然地理解,8位的存储空间为什么能够存储-128~127(-2^7—— 2^7-1)。 而相应地,如果是16位,相应地存储-2^15——2 ^15-1,32位也是类似。

总结:
出于存储正数和负数的需要,我们引入了符号位的概念;
当x<y时,x-y直接运算是错误的,出于这个需求,我们将负数存为反码;
当x>y时,x-y进行运算由于数据溢出,我们无法取反得到结果,但是发现作差结果只比实际结果小1,因此将负数的反码加1,也就是补码的概念。

从符号位到反码,从反码到补码,这些概念的出现,均是有实际计算的需求而产生的,仅仅背诵计算公式便应了那句——学而不思则罔。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

农民真快落

我琢磨着也没人给我打赏呀。。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值