简析二进制补码原理:补码 = 反码 + 1?

前言

在计算机系统中,规定数值一律用补码来表示和存储。因为使用补码可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。

很多人很好奇为什么要使用补码表示和存储?直接使用原码表示多好,看上去更加直观和易于计算。

那么,为什么计算机使用补码比原码更好,又是如何通过补码来计算数值的呢?这其中的原理是什么?

什么是补码?

补码的定义:正数的补码与原码相同。负数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)再+1,即为负数的反码+1。

要了解补码首先要了解“模”,模是补码的基础,“模”是指一个循环周期的最大值,当超过这个最大值后就会开始新的周期,例如时钟的一个周期最大值是12,所以模就是12;一周的模是7天;一天的模是24小时。

补码就是通过“模”将减法变加法,通过最形象的时钟能最好理解:

假设当前时针指向8点,而准确时间是6点,调整时间可有以下两种拨法:一种是倒拨(逆时针旋转)2小时:8-2=6;另一种是顺拨(顺时针旋转)10小时:(8+10)%12=6,这样就有 (8-2)%12=(8+10)%12=6

通过这个简单栗子,可以看出在以12为模的系统(时钟)里,+10和-2效果是一样的,因此凡是-2操作都可以用+10来代替,凡是+10操作都可以用-2来代替,所以对“模”而言,-2和+10互为补码。

通过这个原理,我们还能得出还有-3和9、-4和8等等都互为补码,观察所有补码规律,得出互为补码的两个值的绝对值之和等于模

为什么会这样呢?简单理解就是因为补码补码,就是要补的,要把数补满到模。

有人可能会说,符号都不同一个正一个负,怎么能补满到模呢?

其实这里就陷入了一个认知误区了,因为符号是人为定义的,符号的不同只是表示方向不同而已,你能从时钟里找到数值的正负号吗?如果我把顺时针定义为-,逆时针定义为+,那么+2和-10一样互为补码,这有什么区别吗?

所以一个负数的补码等于模减去负数的绝对值:x = -y mod n = ( n - y ),而正数的模运算等于本身所以补码等于本身。

补码的运算原理

继续通过这个时钟的栗子,我们再来看一下如何使用补码进行运算:

1、8 + 8 = ( 8+8 )%12 = 4:8点顺拨8个小时到4点。

2、6 - 11 = ( 6+ (12-11) )%12 = 7:6点倒拨11个小时到7点。

如果从数值计算来看,第二个例子的结果应该是-5,没错,这也是有无符号数的区别。

我们继续使用时钟举例,时钟是典型的无符号数,如果我们现在需要给时钟的数值加符号,来表示正负数,应该怎么办才好?

首先因为要分正负数,所以时钟数值应该对半分,正数的范围为[1, 6],负数的范围为[-5,-1],其中0即模12既不是正数也不是负数。

通过上面补码的原理,7和-5、8和-4、9和-3、10和-2、11和-1互为补码,所以我们就可以用7、8、9、10、11来表示-5、-4、-3、-2、-1,可以画个时钟来看一下。

本质上,时钟的数值并没有变,只是数值表示的含义变了。7在无符号数中表示7,在有符号数中表示-5,但在运算中都是用7来计算。这也是为什么使用补码符号位可以参与运算,因为符号位本身就是人为定义的,而数值本身并没有改变,在运算中从来没有考虑过符号位,仅用单纯的加法运算进行运算。

使用补码计算得到的也是补码,所以第二个例子的结果是7(-5的补码)是正确的。

补码 = 反码 + 1?

为什么负数原码除符号位外逐位求反再+1,就可以得到其补码?

我们首先来看反码,1 + 0 = 1、10+01 = 11、101+010 = 111,通过最简单的三个例子,我们可以知道任何一对反码相加必然得到模下的最大值,但没补满到模,+1就刚好补到模。

为什么符号位不取反? 因为负数原码就是在将正数原码的符号位取反的结果,已经取反过一次了自然无需再取反了。

本文采用比较易懂的解释来阐述补码的原理,可能不严谨,多多见谅。

那看完本文的你们能解答下面的问题了吗?

1、什么是补码?补了什么?怎么补的?

2、为什么最高位为0的表示正数,最高位为1的表示负数?

3、为什么符号位能够参与运算?

4、为什么正数的原反补码都是它本身,而负数的补码等于原码的反码+1?

注:本人水平有限,如果文中解释有误,希望能指出,或者有什么建议可以一起探讨,共同进步。

参考文章

二进制补码计算原理详解

原码, 反码, 补码 详解

猜你喜欢

转载自blog.csdn.net/qq_36557133/article/details/107580584