个人对原码-反码-补码的理解

1.原码、反码、补码

以下都是基于8位机器来讨论。

原码

  正如我们学习的十进制与二进制转换一样,这种原码的二进制表示显得很自然(尽管,对于进制而言,也有一些晦涩难懂的部分,这里先不讨论)

反码

  由于计算机内部使用的是二进制,因此才会存在反码,因为它就两种状态,才有正反的概念。反码也很简单,就是码按位取反。反码因为是按位取反,它与原码相加,是不会进位的,原码 + 反码 = 模 -1。(模概念下面讲)
就这里出现的反码,只是一个中间量,它的出现只是为了让我们计算补码。

补码

  对于第一次接触来说,补码是一个新奇的概念。补码 = 反码 + 1。这里我们可以与上面源码反码的关系进行结合,可以得出,原码 + 补码 = 模

  这几句结论很简单,但是其实我思考的时间跨度很长,当我终于明白到到补码的意义后(尽管还只是50%理解),确实有一点豁然开朗的感觉。如果你不能用自己的话去解释一样事物,请不要说你懂,你只是会使用。当然,会灵活使用才是生产力。


2.为什么要有反码和补码

  原码的概念,是很自然的,而基本上,出现反码,补码的原因,是基于硬件设计难度与效率的考虑导致的。

  • 计算机只有加法器(加法最容易实现,速度最快,貌似有曾有减法器,只是效率问题不用了)
  • 计算机有固定的位数,对同一个结果,可以向两个方向转换获得,也就是在这个循环的容器里,加和减是相对的,减法都可以转换为加法。
    而补码就是为了解决减法转换加法而出现的。

3.只使用补码

  尽管一个数值,有原码,反码,补码的区别,但是,实际上,并没有必要同时使用3个码,计算机只需要存储补码即可。因为补码用于运算是很方便的,同时,也能通过补码区分出不同的数值。那其他两个码的作用,只是为了让我们去理解,它有它的意义,也有它的作用,只是在计算机内部存储时,不需要用到原码,反码。


4.什么是模

  我所理解的模,是一个有限循环的容器,可以表示出的最多的可能数,简单理解成最大组合数值(不是数值)。这个可能数,就是我们的模。
  针对8位机器,它只能显示2的8次方种可能,也就是256,最大表示数值是255,再往上加就会溢出,从新从0开始。那么,它的模就是256(尽管最大的表示数值是255,那是因为我们从0开始数起)。
对于我们常见的指针时钟,它的模是12,因为它可以表示12种可能,而且循环。
  再想想我们的三角函数,2π。


5.为什么正数3码合一?

  按照“规定”,正数的原码,反码,补码是一样的。
  但其实,如果理解为什么要出现补码,那也可以理解一下为什么正数要3码合一。补码的出现,其实是为了统一所有的运算方向。
  例如,时钟有顺时针,逆时针调整。有了补码后,都可以按照顺时针调整。或者可以理解成,补码就是顺时针方向上的数值,那既然补码的意义是这样,正数本来已经在需要调整到的目标方向上,那它的原码就已经是补码了。那多出来的反码呢?既然整数的原码,补码相同,那么反码真的就规定它与原码相同吧,因为正数本来就不需要反码。
  所以,最终结果就是整数3码合一了。


6.减法是如何变成加法的?

  在存在模的系统里,由于模的存在,也就允许了减法向加法转换。
  不明白?我们看一下我们的指针式时钟。
  当前时间5点,我们要拨到3点,我们可以顺时针拨10格,或者逆时针拨2格。
  相当在这个时钟系统里,计算5-2。
  这个时候,我们就可以添加一个模,添加这个模后对运算结果并没有影响(想想高中的三角函数,针对一个特定的角度我加2π的效果),这时候计算的式子相当于

5-2+12 >>>>> 5 + 10 >>>>> 15 >>>>> 12 + 3 >>>> > 3

  只显示大于0,小于(模-1)的值。最终指向3这个位置。
  由于减数的范围不可能超过模的大小(我们从0开始算,那么减数最多等于11),因此,添加一个模再做减法运算后,可以保证将减法转换为加法。


7.为什么是[-128,127]?

  有没有想过这个问题?既然拿出一个位作符号位,那么8个位的表示范围应该是[-127,127]才对呀?为什么书本都是[-128,127]?难道书本印错了?我当初也是这种想法,于是我一直在寻找这个答案。下面揭晓。
  本来,抛开其他因素,我们就看1个符号位,7个数值位的话,表示范围确实应该是[-127,127],但是,回来实际情况,对于有符号的char类型,却存在一个正负0的问题(就是起点重复了)。
  我们只看数值的补码。
   正0: 0000 0000
负0(原): 1000 0000
负0(补): 1000 0000
  这就很奇怪了,不可能存在两个0,我们要保证表示的唯一性。我们肯定要实至名归的正0的,负0该怎么办?
  我们知道对于负数而言,它是以补码形式存放的,因此,在实际存放时,负0依然表示为1000 0000(少年,自己算一算),我们再看看-127的补码:1000 0001,我们会发现,负0比起-127,在补码上的数值差1,负0的补码比-127的补码少1,那说明了什么问题了?也就是负0的补码可以用来表示-128。神奇吗?很神奇。至少我是思考了很久,而且参考了很多资料后才想明白这个问题的。所以,最终的结论就是,针对有符号的char类型(这里按8位),多出来的负0,正正是表示-128的补码。
  嗯,负0是-128的补码。这个知道了,那-128的原码呢?
  如果正常来说,-128的原码应该是1 1000 0000(少年,请参考-127的源码1111 1111),变成了9位,这是不可能的。
  按我自己的想法,根本不需要考虑-128的原码,既然是使用补码形式存储,那么负0作为的补码就是-128。补码也是表示数值的一种方法。


结语

  原码,反码,补码,刚开始接触是不好理解的,这并不是一句规定就可以解释的问题,每天上亿的机器依据这些“规定”来进行运算,你的银行存款,你的移动支付,都有着各种数值变化,不可能单单规定就可以保证它的正确性,这里面必须有完善的逻辑在里面。个中原理当然需要我们花时间去思考理解。
  以上仅是我个人的理解,也会有偏差,如果你有更好的理解,欢迎留言交流。^-^。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值