源码、补码原理详解

说在前面

我们都知道在计算机中有原码和补码这两个概念。其目的是为了解决在计算机二进制运算中负数的问题,即减法问题。在计算机中,我们使用补码来描述负数。但许多人都不明白为什么这样做,大家都只知道正数的补码是它的本身,负数的补码是取反加1。但是为什么我们需要补码这个东西?补码又是什么玩意儿?许多人都不太明白。

之前因为工作涉及不到相关的知识点,所以也就一知半解。后来仔细研究了下才发现其中大有深意,不禁为前辈先贤们的智慧所折服。

我们之所以需要这么一套补码的机制,其实只是因为我们想要在计算机中完成减法运算。计算机中只有加法器,没有减法器。那么如何利用加法器完成减法运算就是一个需要解决的问题,由此我们今天所要讨论的话题就诞生了……

模和补数

紧接着上面的话题,我们要在计算机中通过加法器进行减法运算,这其中势必需要做某些神奇的操作。加法和减法是两个相反的动作,如何进行呢?

首先让我们看几个生活中的栗子:

  • 时钟满12点的时候归0,时钟时针顺时针走1格和逆时针走11格从结果上来看是等价的
  • 一个圆的角度是360度,顺时针旋转90度和逆时针旋转270度从结果上来看也是等价的
  • 十进制数82减去25,和82加上75,如果忽略掉进位(周期)的情况下也是等价的

由上面几个实例发现,其中三组数字有以下关系

  • 1+11=12
  • 90+270=360
  • 25+75=100

其中12,360,100我们称之为模,而1和11,90和270,25和75是三组“互补”的数字,其互为补数。

模都是具有周期的数字。通过上面3个事例我们发现:在忽略周期(也可以称为进位)的时候,相反的两个操作得到的结果却是等价的。
假设逆时针为减法操作,顺时针为加法操作,则以上三个例子可有下面表达:

-11(时钟逆时针旋转11格)=1(顺时针1格)-12 (模)
-90(角度逆时针90度)=270(顺时针270度)-360(模)
82-25=82+(100-25)-100=82+75-100(模)

注:周期是我个人加的一个概念方便理解,可以理解成进位,如两位数运算满10就会向百位进位一样

通过以上得知,两个相反的运算可以通过对应的补数和减去模来进行变型。如82-25可以变成82+75,这样一来我们只要在计算结果时将进位给舍弃掉就能得到正确的结果,我们不就将减法变成了加法了吗?
当然如何舍弃进位肯定不能向上面那样直接减去100来计算,好不容易将减法变成加法,又引入减法运算不是有绕回来了吗?这一波神奇的操作还是要放在实际的计算机环境,也就是二进制中来讲。

二进制的原码和补码

上面我们讲了十进制的82-25在忽略进位的时候等价于82+75。由此可以将减法变为加法。那么在二进制中是否也是这样?

我们以8位二进制数来计算(其模为10000,0000),82-25:

82: 0101,0010
25: 0001,1001 其补数为 10000,0000 - 0001,1001=1110,0111
照上面的规律则:

    0101,0010						0101,0010
 -  0001,1001			等价于    +  1110,0111
---------------------           ---------------------
								   10011, 1001

10011,1001忽略最高位即为57,可见通过以上补数的规律计算二进制是可行的。而二进制的补数,我们给他换了个名字,称为补码。而我们通常所说的求二进制的补码,其实就是求补数(即模减去其本身的绝对值)。由于二进制的模除最高位是1其余为全是0,在做求补数运算的时候,两者相减,0变1,1变0,模的最高位被其他地低位借位这样运算的结果就和我们的口诀“按位取反,加1”的结果是一致的。

“按位取反,加1”实际上也是计算机在计算补码的方式。但是由于这个口诀,模糊了我们队求补码的本质认识。

记住,求补码本质上是在求补数,是为了将减法运算变成加法运算

二进制中符号位的由来

我们习惯将最高位作为符号位来区分二进制的正负数。但是我们从来不知道为什么要这样做。

还是从十进制说起,上面说了82-25等价于82+75。这时大减小的情况,但如果是小减大呢?如25-82。按照我们上面补数的相关知识,25-82等价于25+18=43。但是-63和43是两个不同的东西,这里也没有进位问题,我们没法通过忽略进位来得到我们想要的答案。那么这样改怎么处理?是否我们可以逻辑上规定-63和43就是同一个东西,即-63的正数表达方式就是43呢?
实际上是可以的,并且我们的先辈吗就是这样规定的。

但是者出现了一个问题,如果43代表了-63,那么43就不能代表其本身了,不然这样就乱套了,因为一个值不可能同时代表两个不同的数。

那么肯定就有所划分,将一定数量的正数用于表示负数,而其他剩余的正数代表其本身。这样一来,0–99刚好一般用来代表负数,一般用来代表正数。如0–49代表正数,50–99代表负数。那么98就代表-2

回到二进制数,以8位二进制数为例。由于我们需要一半的数来表示负数,这些表示负数的数即为其绝对值的补数。由于我们规定正数的补码为其本身,所以1和-1的补码其实是互补的。所以你会看到一个范围中一般的大值刚好能够表示小值部分的负数。

在这里插入图片描述

同时观察补码0127表示的是正数0127 补码128255表示的是负数-128-1这样进行规定划分后,用于负数的二进制高位均为1,而正数二进制高位均为0。这样有一个好处,当计算机在进行计算时只需要判断高位是1还是0就可以分辨其为正数和负数。这便是最该位的由来。

由此我们知道为什么对于N个字节所能表达的值的大小范围为-2^(n-1) ~ 2^(n-1)-1之间了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值