-
2020-07-23 13:52:43
二进制负数的在计算机中采用补码的方式表示。很多人很好奇为什么使用补码,直接使用原码表示多好,看上去更加直观和易于计算。然而事实告诉我们,这种直观只是我们人类的一厢情愿罢了,在计算机看来,补码才是它们最想要的。那么,为什么计算机使用补码更好,又是如何通过补码来计算数值的呢?
我看过网络上很多解释补码的文章,几乎一致的回答就是符号位不变,其他各位逐位求反再加一。在此我想说,这些都不是根本原理。谁都知道这么求,数电第一章就明确写了怎么求,关键是为什么这么算,其中的原理是什么?
本文主要的内容就是深入讲解补码的原理,其中内容有相互引用成分及计算机基础要求,不适合初学者阅读。当然,随便看看无所谓啦。
1.什么是补码
这个没有找到官方定义,只进行个人定义。
个人定义:补码是计算机中用来表示负数,使得负数能够使用加法器参与加法运算的一种码。
加减是计算机中最常用的运算,加法一般使用加法器来实现,减法则使用减法器实现。那有什么办法可以将减法变为加法,这样就可以让系统只实现加法即可,答案就是补码。
理解补码最简单的例子就是时钟。
例1:
假如一个时钟现在显示的是10点钟,如何将它调到6点钟?
解:有两种方法,一是向后拨8个小时,二是向前拨4个小时
在这个例子中,8 和 4 互为补数,也就是说4的补码是8,8的补码是4,而这个时钟的模就是12
注意:可能有人会想,在往后调8个小时虽然也调到了6点,但是他实际上比原来日期多了12小时。是的,的确如此,但是你的时钟有地方存储了这多余的12个小时吗?答案是没有,所以在你调完后,你没有记录这12个小时,换句话说,你把这溢出的12个小时自动舍弃了。当第二个人来查看闹钟时间的时候,他看到的时间就是准的。
例2:
一个数的数值是11,他的模是16,那么他的补码是多少?
解:16-11 = 5,即补码就是5。
2.模
关于模没有找到固定的定义,简单来说模就是一个循环的周期,在例1中,时钟的一个周期就是12,所以模是12。一周的模是7天,一天的模是24小时。模是补码的一个重要概念。
3.使用补码运算
例3
模为32,使用补码运算该算式16-13,13 - 16。
解 16-13 = (16 + (32-13))% 32 = 35 % 32 = 3
13-16 = (13 + (32-16))% 32 = 29 % 32 = 29
4.使用补码进行二进制运算
有看过数电基础的都应该记得,第一章就有说明二进制补码是如何运算的。正数的补码即为自己,负数的补码为符号位不变,其余逐位求反再加1。
使用该定义,先通过例子求出数值,再对例子进行详细讲解,为什么可以使用负数的补码来运算。
例4 通过二进制求15-11的值
要想让减法变加法,必须转换算式为 15 + (-11)
15为正数,符号位为0,二进制表示为 01111
-11为负数,符号位为1,负数原码为 11011 ,补码符号位不变,其余逐位求反再 +1,即 10101
所以 15 + (-11) = 01111 + 10101 = 100100 舍弃第一位溢出位,即00100,即+4
这是一个最简单的补码算法运算的例子,却有很多不解之处。
1.为什么负数 (-11 )逐位求反再+1就可以代表原来的数?
2.为什么第一位舍弃
3.为什么符号位能够参与运算
先看问题1,-11 先不考虑符号,观察11的二进制表示,11使用二进制表示是 1011,将1011 逐位求反 得到 0100,因为是逐位求反,1011 +0100 = 1111 ,而1111 + 1 = 10000,发现了什么?10000是四位2二进制数的模。为什么10000是4位二进制数的模呢?原理也很简单,4位寄存器最高能表示什么数?即 (二进制)1111 = (十进制) 15 , 15 +1 =16 = (二进制)10000,后四位寄存器清0,所以模为16。
所以不管几位二进制数,取反后得到的值加原码会刚好的到所有的位都是1的二进制数,再加一就刚好进位得到模。所以取反加一是无论如何都能取到补码的。比如 :(原)101 + (补)((反)010 +1) = 8 ,(原)10 + (补)((反)01 +1)= 4。
所以,负数符号位不变,其余逐位求反 +1 只是算出补码最简单的方法,而不是理论基础。
前面提到过,使用补码代替原码,计算后模掉溢出得到数值就可以得到计算的值了。
再看问题2,为什么高位舍弃,这个问题其实在例1中已经做了说明,因为你没有存储这个高位的空间,用最简单的解释来解释就是,一个4位的寄存器,只能存储数据的后四位,第一位进位没地方放,就像例1中多出来的12小时,没有地方存储,那么就丢弃了,反正结果正确就行。可能有人会问,你说丢弃就丢弃吗,丢了你怎么保证是正确的?
重新再看一次例4,现在考虑符号位,将符号位加入运算。
15 - 11 = 15 + (-11),其中 -11 为 11011(加了一位符号位,所以模为 16 * 2^1) 他的补码为 10101 = 21
所以 15 -11 变为 15 +21 = 36 (01111 + 10101) ,原先是减一个数,变换后却变成了一个比减数更大的加数了,能不溢出吗。所以要模掉溢出位 36 % 32 = 4 。仔细观察被模数36 = 1 00100 你会发现,在第二位之前的所有高位都是32的倍数,所以用32进行模运算就会全部清0,这就是为什么高位可以直接舍弃的原因,因为高位永远会是模的倍数,在模的过程中会被清0。
最后看问题3,为什么符号位能够参与运算,可能在这前面一直被符号位困扰,为什么参与运算就没有问题,看了这里的解释,我相信你讲不会再被困扰。
符号位对于我对二进制补码的理解产生了很大的阻碍,我不明白为什么符号位可以参与运算,而且算出来还是对的。花了不少时间理解了符号位的含义。
首先放弃符号位就是计算机表示专门定义出来表示正数和负数用的这个思维,换成这样一种理解思路:我们观察计算机中一个二进制数,它没有专门的符号位,但是正数和负数在计算机中存储第一位二进制数会存在差异,如果它的第一位是0,那么他就是正数原码,如果它的第一位是1,那么他就是负数补码,我们通过观察第一位是0还是1即可知道这个数是正数还是负数。
通过以下例子,可以发现符号位其实是算出来的。
例5:计算机运算 9 - 12
解:9 转五位二进制为 01001 //模为32(100000)
因为12是减数,所以将12转为补码变为加数,方便参与加法运算
12 = 01100(原) = 10011 + 1 = 10100(补)
01001 + 10100 = 11101
11101% 100000= 11101
从结果看,我们可以发现,第一位为1,第一位如果是1,那么这个数值是负数补码,由此可知,这个数是一个负数,只是在计算机中,他表示为11101,反求原码,即可得到 (11101 - 1) 反 = 00011 = 十进制数 3,由此可知,11101表示的是负数的3
从这个例子当中可以看到,在运算中完全没有考虑符号位,仅用单纯的加法运算进行运算,而得到的结果11101也没有人为去添加一个符号位,符号位是计算所得的,所以他才能参与运算。我们应该反过来看符号位,正是在补码运算中,存在第一位为0则是正数,为1则是负数这个规律,我们才方便地认定第一位为符号位,符号位跟人为定义没有任何关系(人为定义的符号位不可能满足数学规则参与数学运算)。
补充:在例5中可以发现,我们在第一位之前补了一个0,将四位二进制数补成五位二进制数来计算,为什么要补这个0呢?为了说明这个问题,我们来算一个错误的运算
例6:计算机运算 0 - 12
解 : 我们仅仅用四位二进制数(四位寄存器)来算
12 = (二进制)1100 12转为二进制后是一个四位二进制数,它的模为10000
因为12是减数,所以将12转为补码变为加数,方便参与加法运算
12 = 1100(原) = 0011 + 1 = 0100(补)
0000 + 0100 = 0100 = 4 ,第一位是0,说明是正数原码, 即运算结果为 +4
4 != -12 运算出错
通过结果发现,只用四位二进制数运算,结果是错误的,为什么会产生这种错误呢?因为寄存器位数不够,四位寄存器只能存储 0 -15 的数值,没有多余的寄存器位置用来表示这个数的正负,我们虽然算出了符号位,但是计算后所得到的符号位却没有地方存放,导致符号位缺失,我们又误将四位二进制数结果的第一位当做符号位来判断数的正负,才会出现错误的结果。
通过例5我们可以知道,符号位是计算后得出来的,所以我们要预先要在寄存器第一位留出一个位置存放计算后得出的符号位,所以我们先在第一位前面补一个0占位。
由此可知: 要想计算结果正确, 需要满足 : 寄存器位数 >= max(操作数1,操作数2,....) 的二进制位数加一位
最后,附上一张五位二进制数运算转换关系图,自己体会二进制数如何带着所谓的符号位在计算机中运算:
有如下几点:
1:五位二进制数的所有正数都在圆环的黑线上,而负数都在圆环的红线上,如果在黑线上,那么六位寄存器第一位必为0,而在红线上,那么第一位必为1,我们也是通过这个位来判断数值的正负
2:五位二进制数运算结果取模后如果在黑线上,那么为正数,否则为负数
3:尝试写几个数字转为五位二进制数或者写几个算式对号入座,观察是否符合,加深理解
到这里补码的原理就差不多讲清楚了,无非是使用模进行转化,但是我们站在十进制的角度,去看二进制的东西,的确会显得相当费解。最后我想说,能发明补码来计算的数学家真的是太厉害了。
内容有相互嵌套成分,阅读后回顾前面的内容可能会更加深入理解。
还有很多特殊情况没有考虑,只讲解了最核心的内容。
本文纯属个人理解,如有纰漏,请勿拍砖。
更多相关内容 -
MATLAB 的二进制补码:计算十进制数的二进制补码。-matlab开发
2021-06-01 21:18:33在 MATLAB 中计算有符号整数的二进制补码。 -
二进制补码字符串:二进制定点二进制补码字符串和十进制数之间的转换。-matlab开发
2021-05-30 16:02:35这些函数像内置的 MATLAB 函数 BIN2DEC 和 DEC2BIN 一样在二进制字符串和十进制数之间进行转换,但可以容纳负整数(通过二进制补码)和分数正负数(通过二进制补码固定点和字符串中的二进制小数点)。 请注意,许多... -
二进制补码详解
2022-03-27 10:29:49微处理器用二进制补码系统表示有符号整数,因为它可以将减法运算转换为对减数的补数的加法运算,详解如下。微处理器用二进制补码系统表示有符号整数,因为它可以将减法运算转换为对减数的补数的加法运算。
1.什么是二进制补码运算
我们先引入补数的概念:
补数:一个数与它的补数之和是一个常数。例如一个一位的十进制数与它的补数之和总是9,2的补数是7,4的补数是5。在n位的二进制算术中,数P的补数Q=
-Q(即常数是
)。
令n位二进制数N的二进制补码定义为
-N。如果N=5=00000101(8位二进制数),则N的补码为
-00000101=100000000-00000101=11111011(注意此处11111011用于表示5的补码,不要看成无符号整数)。
下面看几个例子:
5:00000101,5的补码:11111001
7:00000111,7的补码:11111001
例1:将7与5的补数相加
00000111 + 11111011 = 1000000010
结果为9位二进制数100000010。由于一共只有8位,我们忽略最左边一位,结果为00000010,也就是2。即7与5的补数相加结果为2,效果等同于7-5=2。
例2:将7的补数与5相加
11111001+00000101=111111110
结果为9位二进制数111111110,忽略最左边第九位后结果为11111110,“刚好”是二进制2的补码(
-00000010=11111110),也就是5-7=-2。
从上述例子看,在二进制运算中,对于正数N而言,减去N的操作和加上N的补数的操作效果是相同的,也就是说-N等价于N的补数。
那么,为什么要引入补码运算呢?
2.用补数的加法代替减法
二进制补码算术不是魔术,具体展开看,在n位的二进制算术运算中,我们令Z=X-Y,我们试着用X加上Y的补数来运算,由于Y的补数为
-Y,所以
X+Y的补数=X+(
-Y)=
+(X-Y)=
+Z
换句话说,我们用X加上Y的补数会得到Z加上
,但
只体现在最左边的第n+1位(如同上述例子中第九位的1),会被丢弃掉。所以此时我们得到了Z=X-Y=X+Y的补数,也就是说,在二进制补码运算中,减去一个数,等同于加上这个数的补码。
到这里,我们可以进一步直接放心地在二进制补码运算中用一个数的补码来表示这个数的负数了,如果不放心,我们还可以证明,对一个数进行两次求补将得到这个数本身:例如
-5=
-00000101=11111011
再次求补:-(-5)=
-11111011=00000101=5
我们考虑加法的所有情况,请看下面的实例。令
X=9=0000101, -X=11110111
Y=6=00000110, -Y=11111010
此时有
X+Y=00000101+00000110=00000111=15
X-Y=00001001+11111010=100000011=3(红色最高位舍弃)
-X+Y=11110111+00000110=111111101=-3(3的补码)
-X-Y=11110111+11111001=111110001=-15(15的补码)
结合之前所有的论证, 上述所有4中加减法中的情况都正确得到了我们想要的结果,例如将6与9的补码相加完成运算-9+6,得到-3,确实是3的补码。
3.求补运算
我们现在可用补码加法来代替减法了,但是,例如N的补码是
-X,我们求补的操作本身不就是一次减法吗?!别急,补码运算可没这么蠢,求补的运算是非常简单的。我们将表达式
-X表示为下面的形式:
例如,8位(n=8)时有
表达式111...1-X的值很容易计算。对于X的第i位
,如果
=0,则1-0=1,同样,若
=1,则1-1=0,很显然,取
的反就行了,换句话说计算111...1-X部分的值只需要将X每一位取反。可见计算X的补码非常容易:
计算数N的补码,所要做的就是将X的每一位取反,然后将取反结果加1。
例如,对于二进制的6=00000110,6的补码为11111001+1=11111010。
这种补码运算相对于减法来说,非常适合用硬件实现,效率也很高。
4.补码的特点
- 补码是一个真正的互补系统+X+(-X)=0;
- 补码0被表示为00...0,是唯一的;
- 补码的最高位为符号位,如果符号位为0,则该数为正;符号位为1,则该数为负;
- n位二进制补码数的表示范围为(-
)~(
-1),例如对于n=8,补码的范围为-128~127.共有
=256个不同的数(128个负数,1个0,127个正数);
- 补码加法和减法可以使用同样的硬件完成,因为补码减法由被减数加上减数的补数实现。
5.运算溢出
n位二进制补码数的表示范围为 (-
)~(
-1)。如果运算结果位于这个范围之外会发生什么呢?
我们令5位有符号二进制补码数的表示范围为-16~+15,考虑下面的例子:
情形1:5+7=00101+00111=01100=12
情形2:12+13=01100+01101=11001=-7
在情形1中,我们得到了期望的结果+12,但在情形2中,我们得到的结果是一个负数,因为它的符号位是1,如果将他视作无符号整数,它将是
,但是我们不可能将两种解释应用到一个表示方法中,所以一旦采用了补码表示,那么11001就只能表示-7。
同样,如果两个负数相加且结果小于-16,也会超出5位二进制补码的表示范围。
情形3:-9-12=10111+10111=101011
在情形3中,第六位1舍弃后,结果为正数01011=11。
这两个例子都说明了什么是运算溢出,它发生在补码加法当两个正数的和为负数,或两个负数的和为正数的时候。也就是说,如果操作数A和操作数B的符号位相同,但结果的符号位与它们不同的时候,则可以判定发生了溢出。
-
二进制补码计算原理详解
2018-07-03 17:34:54二进制负数的在计算机中采用补码的方式表示。很多人很好奇为什么使用补码,直接使用原码表示多好,看上去更加直观和易于计算。然而事实告诉我们,这种直观只是我们人类的一厢情愿罢了,在计算机看来,补码才是它们最...二进制的负数在计算机中采用补码的方式表示。很多人很好奇为什么使用补码,直接使用原码表示多好,看上去更加直观和易于计算。然而事实告诉我们,这种直观只是我们人类的一厢情愿罢了,在计算机看来,补码才是它们最想要的。那么,为什么计算机使用补码更好,又是如何通过补码来计算数值的呢?
我看过网络上很多解释补码的文章,几乎一致的回答就是符号位不变,其他各位逐位求反再加一。在此我想说,这些都不是根本原理。谁都知道这么求,数电第一章就明确写了怎么求,关键是为什么这么算,其中的原理是什么?
本文主要的内容就是深入讲解补码的原理,其中内容有相互引用成分及计算机基础要求,不适合初学者阅读。当然,随便看看无所谓啦。
1.什么是补码
这个没有找到官方定义,只进行个人定义。
个人定义:补码是计算机中用来表示负数,使得负数能够使用加法器参与加法运算的一种码。
加减是计算机中最常用的运算,加法一般使用加法器来实现,减法则使用减法器实现。那有什么办法可以将减法变为加法,这样就可以让系统只实现加法即可,答案就是补码。
理解补码最简单的例子就是时钟。
例1:
假如一个时钟现在显示的是10点钟,如何将它调到6点钟?
解:有两种方法,一是向后拨8个小时,二是向前拨4个小时
在这个例子中,8 和 4 互为补数,也就是说4的补码是8,8的补码是4,而这个时钟的模就是12
注意:可能有人会想,在往后调8个小时虽然也调到了6点,但是他实际上比原来日期多了12小时。是的,的确如此,但是你的时钟有地方存储了这多余的12个小时吗?答案是没有,所以在你调完后,你没有记录这12个小时,换句话说,你把这溢出的12个小时自动舍弃了。当第二个人来查看闹钟时间的时候,他看到的时间就是准的。
例2:
一个数的数值是11,他的模是16,那么他的补码是多少?
解:16-11 = 5,即补码就是5。
2.模
关于模没有找到固定的定义,简单来说模就是一个循环的周期,在例1中,时钟的一个周期就是12,所以模是12。一周的模是7天,一天的模是24小时。模是补码的一个重要概念。
3.使用补码运算
例3
模为32,使用补码运算该算式16-13,13 - 16。
解 16-13 = (16 + (32-13))% 32 = 35 % 32 = 3
13-16 = (13 + (32-16))% 32 = 29 % 32 = 29
4.使用补码进行二进制运算
有看过数电基础的都应该记得,第一章就有说明二进制补码是如何运算的。正数的补码即为自己,负数的补码为符号位不变,其余逐位求反再加1。
使用该定义,先通过例子求出数值,再对例子进行详细讲解,为什么可以使用负数的补码来运算。
例4 通过二进制求15-11的值
要想让减法变加法,必须转换算式为 15 + (-11)
15为正数,符号位为0,二进制表示为 01111
-11为负数,符号位为1,负数原码为 11011 ,补码符号位不变,其余逐位求反再 +1,即 10101
所以 15 + (-11) = 01111 + 10101 = 100100 舍弃第一位溢出位,即00100,即+4
这是一个最简单的补码算法运算的例子,却有很多不解之处。
1.为什么负数 (-11 )逐位求反再+1就可以代表原来的数?
2.为什么第一位舍弃
3.为什么符号位能够参与运算
先看问题1,-11 先不考虑符号,观察11的二进制表示,11使用二进制表示是 1011,将1011 逐位求反 得到 0100,因为是逐位求反,1011 +0100 = 1111 ,而1111 + 1 = 10000,发现了什么?10000是四位2二进制数的模。为什么10000是4位二进制数的模呢?原理也很简单,4位寄存器最高能表示什么数?即 (二进制)1111 = (十进制) 15 , 15 +1 =16 = (二进制)10000,后四位寄存器清0,所以模为16。
所以不管几位二进制数,取反后得到的值加原码会刚好的到所有的位都是1的二进制数,再加一就刚好进位得到模。所以取反加一是无论如何都能取到补码的。比如 :(原)101 + (补)((反)010 +1) = 8 ,(原)10 + (补)((反)01 +1)= 4。
所以,负数符号位不变,其余逐位求反 +1 只是算出补码最简单的方法,而不是理论基础。
前面提到过,使用补码代替原码,计算后模掉溢出得到数值就可以得到计算的值了。
再看问题2,为什么高位舍弃,这个问题其实在例1中已经做了说明,因为你没有存储这个高位的空间,用最简单的解释来解释就是,一个4位的寄存器,只能存储数据的后四位,第一位进位没地方放,就像例1中多出来的12小时,没有地方存储,那么就丢弃了,反正结果正确就行。可能有人会问,你说丢弃就丢弃吗,丢了你怎么保证是正确的?
重新再看一次例4,现在考虑符号位,将符号位加入运算。
15 - 11 = 15 + (-11),其中 -11 为 11011(加了一位符号位,所以模为 16 * 2^1) 他的补码为 10101 = 21
所以 15 -11 变为 15 +21 = 36 (01111 + 10101) ,原先是减一个数,变换后却变成了一个比减数更大的加数了,能不溢出吗。所以要模掉溢出位 36 % 32 = 4 。仔细观察被模数36 = 1 00100 你会发现,在第二位之前的所有高位都是32的倍数,所以用32进行模运算就会全部清0,这就是为什么高位可以直接舍弃的原因,因为高位永远会是模的倍数,在模的过程中会被清0。
最后看问题3,为什么符号位能够参与运算,可能在这前面一直被符号位困扰,为什么参与运算就没有问题,看了这里的解释,我相信你将不会再被困扰。
符号位对于我对二进制补码的理解产生了很大的阻碍,我不明白为什么符号位可以参与运算,而且算出来还是对的。花了不少时间理解了符号位的含义。
首先放弃符号位就是计算机表示专门定义出来表示正数和负数用的这个思维,换成这样一种理解思路:我们观察计算机中一个二进制数,它没有专门的符号位,但是正数和负数在计算机中存储第一位二进制数会存在差异,如果它的第一位是0,那么他就是正数原码,如果它的第一位是1,那么他就是负数补码,我们通过观察第一位是0还是1即可知道这个数是正数还是负数。
通过以下例子,可以发现符号位其实是算出来的。
例5:计算机运算 9 - 12
解:9 转五位二进制为 01001 //模为32(100000)
因为12是减数,所以将12转为补码变为加数,方便参与加法运算
12 = 01100(原) = 10011 + 1 = 10100(补)
01001 + 10100 = 11101
11101% 100000= 11101
从结果看,我们可以发现,第一位为1,第一位如果是1,那么这个数值是负数补码,由此可知,这个数是一个负数,只是在计算机中,他表示为11101,反求原码,即可得到 (11101 - 1) 反 = 00011 = 十进制数 3,由此可知,11101表示的是负数的3
从这个例子当中可以看到,在运算中完全没有考虑符号位,仅用单纯的加法运算进行运算,而得到的结果11101也没有人为去添加一个符号位,符号位是计算所得的,所以他才能参与运算。我们应该反过来看符号位,正是在补码运算中,存在第一位为0则是正数,为1则是负数这个规律,我们才方便地认定第一位为符号位,符号位跟人为定义没有任何关系(人为定义的符号位不可能满足数学规则参与数学运算)。
补充:在例5中可以发现,我们在第一位之前补了一个0,将四位二进制数补成五位二进制数来计算,为什么要补这个0呢?为了说明这个问题,我们来算一个错误的运算
例6:计算机运算 0 - 12
解 : 我们仅仅用四位二进制数(四位寄存器)来算
12 = (二进制)1100 12转为二进制后是一个四位二进制数,它的模为10000
因为12是减数,所以将12转为补码变为加数,方便参与加法运算
12 = 1100(原) = 0011 + 1 = 0100(补)
0000 + 0100 = 0100 = 4 ,第一位是0,说明是正数原码, 即运算结果为 +4
4 != -12 运算出错
通过结果发现,只用四位二进制数运算,结果是错误的,为什么会产生这种错误呢?因为寄存器位数不够,四位寄存器只能存储 0 -15 的数值,没有多余的寄存器位置用来表示这个数的正负,我们虽然算出了符号位,但是计算后所得到的符号位却没有地方存放,导致符号位缺失,我们又误将四位二进制数结果的第一位当做符号位来判断数的正负,才会出现错误的结果。
通过例5我们可以知道,符号位是计算后得出来的,所以我们要预先要在寄存器第一位留出一个位置存放计算后得出的符号位,所以我们先在第一位前面补一个0占位。
由此可知: 要想计算结果正确, 需要满足 : 寄存器位数 >= max(操作数1,操作数2,....) 的二进制位数加一位
最后,附上一张五位二进制数运算转换关系图,自己体会二进制数如何带着所谓的符号位在计算机中运算:
有如下几点:
1:五位二进制数的所有正数都在圆环的黑线上,而负数都在圆环的红线上,如果在黑线上,那么六位寄存器第一位必为0,而在红线上,那么第一位必为1,我们也是通过这个位来判断数值的正负
2:五位二进制数运算结果取模后如果在黑线上,那么为正数,否则为负数
3:尝试写几个数字转为五位二进制数或者写几个算式对号入座,观察是否符合,加深理解
到这里补码的原理就差不多讲清楚了,无非是使用模进行转化,但是我们站在十进制的角度,去看二进制的东西,的确会显得相当费解。最后我想说,能发明补码来计算的数学家真的是太厉害了。
内容有相互嵌套成分,阅读后回顾前面的内容可能会更加深入理解。
还有很多特殊情况没有考虑,只讲解了最核心的内容。
本文纯属个人理解,如有纰漏,请勿拍砖。
-
十进制、二进制补码、16进制补码的转换
2021-01-17 17:26:25今天一场技术笔试一道编程题难住了我,算出一个十进制数的二进制补码和对应的16进制,由于时间紧张,加上紧张,做的极差,因此mark以下十进制转二进制补码
首先要明确的是:十进制直接转成二进制是转化为二进制原码,正数的原码和补码相同,但负数的原码按位取反末位加一才是补码。
因此流程图大概如下:
整个代码我贴在最后
主要逻辑代码:
public static String convert(int num) { StringBuilder resultString = new StringBuilder(); // 初始化补码数组,共12位 String[] complementStrings = new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }; boolean ifNegative = false; if (num < 0) { complementStrings[0] = "1"; num = -num; ifNegative = true; } // 加入到补码的数组中,开头从12-strings.length开始 String[] strings = Integer.toString(num, 2).split(""); // 对应在strings数组中的下标 int j = 0; for (int i = 12 - strings.length; i < 12; i++) { complementStrings[i] = strings[j]; j++; } // 如果为负数,先全部取反,否则直接拼接 if (ifNegative) { for (int i = 1; i < complementStrings.length; i++) { if (complementStrings[i].equals("1")) { complementStrings[i] = "0"; } else { complementStrings[i] = "1"; } } // 送进函数加一 resultString.append(binaryPlusOne(complementStrings, 11, 1)); } else { resultString.append(strings.toString()); } return resultString.toString(); }
重要代码1:末位加一
为递归算法,递归逻辑为每次将一位执行与进位的加法并拼接,走完整个数组,返回。
/** * * @param strings 二进制数数组 * @param temp 对哪一位执行加法 * @param carry 进位值 */ private static String binaryPlusOne(String[] strings, int temp, int carry) { if (temp < 0) { StringBuilder tempBuilder = new StringBuilder(); for (int i = 0; i < strings.length; i++) { tempBuilder.append(strings[i]); } return tempBuilder.toString(); } else { // 计算加上进位后的值 int tempInt = Integer.parseInt(strings[temp]) + carry; // 更新对应位置上的值 strings[temp] = String.valueOf(tempInt % 2); // 更新进位 carry = (tempInt) / 2; // 更新坐标 temp--; } return binaryPlusOne(strings, temp, carry); }
二进制转16进制
同样也是递归的思想,每次将二进制字符串最后四位进行转化,并拼接,知道拼完为止。
重要代码
/** * 将二进制转为16进制 * * @param binaryString * @param length * @return */ private static String binaryTo16(String binaryString, int length) { if (length < 4) { return binaryString; } return binaryTo16(binaryString.substring(0, length - 4), length - 4) + binaryTo16Map.get(binaryString.substring(length - 4, length)); }
总体代码,粘了就能用
输入为一个十进制数(其二进制位数在12位以内)
输出为 12位二进制补码和二进制补码对应的16进制码的拼接(以分号隔开)示例:
输入:-7 输出:111111111001;FF9
import java.util.HashMap; public class BinaryCodeTransfer { public final static int totalNumber = 12; public final static HashMap<String, String> binaryTo16Map = new HashMap<String, String>() { { put("0000", "0"); put("0001", "1"); put("0010", "2"); put("0011", "3"); put("0100", "4"); put("0101", "5"); put("0110", "6"); put("0111", "7"); put("1000", "8"); put("1001", "9"); put("1010", "A"); put("1011", "B"); put("1100", "C"); put("1101", "D"); put("1110", "E"); put("1111", "F"); } }; public static void main(String[] args) { System.out.println(convert(-7)); } public static String convertToBase72(int num) { return Integer.toString(num, 2); } public static String convert(int num) { StringBuilder resultString = new StringBuilder(); // 初始化补码数组,共12位 String[] complementStrings = new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }; boolean ifNegative = false; if (num < 0) { complementStrings[0] = "1"; num = -num; ifNegative = true; } // 加入到补码的数组中,开头从12-strings.length开始 String[] strings = Integer.toString(num, 2).split(""); // 对应在strings数组中的下标 int j = 0; for (int i = 12 - strings.length; i < 12; i++) { complementStrings[i] = strings[j]; j++; } // 如果为负数,先全部取反,否则直接拼接 if (ifNegative) { for (int i = 1; i < complementStrings.length; i++) { if (complementStrings[i].equals("1")) { complementStrings[i] = "0"; } else { complementStrings[i] = "1"; } } // 送进函数加一 resultString.append(binaryPlusOne(complementStrings, 11, 1)); } else { resultString.append(strings.toString()); } // 如果大于零直接求出十六进制,否则,放入16进制处理函数中 resultString.append(";").append(binaryTo16(resultString.toString(), 12)); return resultString.toString(); } /** * * @param strings * @param temp * @param carry */ private static String binaryPlusOne(String[] strings, int temp, int carry) { if (temp < 0) { StringBuilder tempBuilder = new StringBuilder(); for (int i = 0; i < strings.length; i++) { tempBuilder.append(strings[i]); } return tempBuilder.toString(); } else { // 计算加上进位后的值 int tempInt = Integer.parseInt(strings[temp]) + carry; // 更新对应位置上的值 strings[temp] = String.valueOf(tempInt % 2); // 更新进位 carry = (tempInt) / 2; // 更新坐标 temp--; } return binaryPlusOne(strings, temp, carry); } /** * 将二进制转为16进制 * * @param binaryString * @param length * @return */ private static String binaryTo16(String binaryString, int length) { if (length < 4) { return binaryString; } return binaryTo16(binaryString.substring(0, length - 4), length - 4) + binaryTo16Map.get(binaryString.substring(length - 4, length)); } }
-
为什么计算机存储的是二进制补码?
2021-07-26 07:39:29正数的反码和原码、补码是一样的 +1 :0000 0001 -1 :1000 0001 1111 1110 1111 1111 -0: 1000 0000 1111 1111 10000 0000 做加法:+1 + -1(补码) 0000 0001 1111 1111 10000 0000 -0 +0 : 0000 0000 -0 : ... -
【二进制】计算机二进制补码
2015-01-14 09:24:51关于计算机世界的二进制 首先,问一个基本的问题。 负数在计算机中如何表示? 举例来说,+8在计算机中表示为二进制的1000,那么-8怎么表示呢? 很容易想到,可以将一个二进制位(bit)专门规定为符号位,它等于0时就... -
二进制补码、小数的补码及运算规则
2015-05-11 15:43:20针对补码这个常见的概念,引申到小数的补码,并且用实例说明其运算规则。 -
java基础 二进制补码
2021-02-12 23:25:41二进制补码:1、计算机系统的内部以二进制形式存储数据。2、在Java程序中输入的十进制的数据都会被自动转换为二进制,Java内部也以二进制来进行数值运算,但返回的结果是十进制。二进制补码的原理:正数+负数=模。模... -
matlab十进制与二进制补码之间的转换
2021-04-18 05:07:24转载:http://blog.xdnice.com/blog40543i59178.htmlmatlab提供了一个系统函数dec2bin,可以用来进行十进制数的二进制转换,不过功能有限!在matlab中键入 help dec2bin,如下:DEC2BIN Convert decimal integer to a ... -
计算机中的加减法(二进制补码加减法)
2021-09-07 22:28:10计算机补码的加减法 因为减法可以转化为加法,所以只考虑加法的四种情况。 正 + 正:结果为正,有可能发生上溢,结果为负。 负 + 负:结果为负,有可能发生下溢,结果为正。 正 - 负:A-B = A+(-B) -
java 整数转二进制补码源代码
2012-12-05 14:57:41整数转二进制补码的源代码 提供了两种方法:一种调用java api中的方法。另一种是自己实现的。 -
二进制的补码
2020-09-14 17:09:50再来看看二进制补码的方式进行计算:-10的二进制补码(11110101 + 1 = 11110110(246)) 二进制计算:00010100 + 11110110 = 100001010 而咱们刚才已经说了,假设计算机是8位的,那么这个结果超过8位,第九位会被... -
c++针对二进制补码算术中整数的算术运算问题,请大神指点
2018-07-06 03:48:10在二进制补码计算中,9+ -14=-5。 #include iostream> #include cmath> #include string> using namespace std; int main() { //Read in the bit pattern size int L; do { ... -
二进制补码乘法除法_二进制乘法和除法
2020-07-23 10:09:19二进制补码乘法除法 1)二进制乘法 (1) Binary Multiplication) Binary numbers can be multiplied using two methods, 二进制数可以使用两种方法相乘, Paper method: Paper method is similar to multiplication ... -
2---MATLAB将十进制转换成二进制补码
2017-09-25 10:37:18MATLAB中提供了一个将十进制转换为二进制的函数dec2bin,但是该函数只能接受大于0的数,也就是不能直接将负数转换为二进制补码。那如何在MATLAB中生成补码呢?我们都知道负数的补码为其反码加1,然而MATLAB中的二... -
使用二进制补码算法的一类定点数字滤波器的稳定性判据
2021-03-05 13:51:18提出了使用二进制补码算法的一类数字滤波器的新稳定性准则。 通过数字示例显示了所获得结果的有效性。 -
二进制补码和十进制数的转换
2020-04-03 23:24:58先考虑如何将二进制补码转换为十进制整数: 若符号位是0, 则该数是正数, 原码等同于补码. 可以由原码(也就是补码)得知代表的正整数. 若符号为是1, 则该数一定是负数, 可按照以下方式转换: 方式一: 先把符号位去掉, ... -
将二进制补码字符串转换为十进制整型数字
2021-07-02 17:43:43要求将文件中二进制补码立即数转为十进制数,写的时候本来想偷个懒找一段,没搜到。 照着一位仁兄的改了改,改成了补码的。 参考: C语言把二进制转换为十进制数的方法和示例 代码如下:注释简单解释了下 #include&... -
二进制补码转为十进制
2021-09-20 13:19:19二进制补码转为十进制整数 package kevin.demo; import java.util.Arrays;import java.util.Scanner;public class Hello { public static void main(String[] args) { Scanner in = new Scanner(System.in); String ... -
关于二进制补码及补码加法的思考
2021-09-06 19:56:13笔者刚学数字电路,就在二进制补码处踩了许多坑,下面就来写一下我对二进制补码的感悟。 提示:以下是本篇文章正文内容,下面案例可供参考 一、生活中了解补码 首先展示一下求补码的公式N(补)=R^n-N 这里的N是原码... -
输出二进制补码
2020-07-18 13:32:09输入一个整型(int)的整数,输出它的32位二进制补码。 输入 一个整型整数。 输出 输出一行,即该整数的补码表示。 样例输入 7 样例输出 00000000000000000000000000000111 知点 第一位为符号位,0表示正数,1表示负数... -
计算机中的负数:二进制补码
2021-01-01 00:02:25二进制运算 计算机中,数值的运算都是用二进制表示的。 一个二进制数中,最高位是符号位,0 为正数,1 为负数。 6 的二进制:0000 0110 8 的二进制:0000 1000 -8 的二进制:1000 1000 如计算: 6 + 8 ... -
C语言 十进制转二进制补码(正负都可) 指针 初学
2019-12-20 22:36:42十进制转二进制补码(正负都可) 指针初学 将一个十进制正(负)整数转换为对应的二进制补码(用指针完成 十进制转二进制:1.先判断该整数是正数还是负数 如果是正数则二进制补码首位为1 , 且对应的二进制补码就是原. 如果... -
计算机二进制中的原码,反码,补码
2020-11-23 10:59:25比如下面的几个数字: 十进制数 2 3 -2 -5 二进制原码 0010 0011 1010 1101 二进制反码 0010 0011 1101 1010 二进制补码 0010 0011 1110 1011 我们用4 位二进制补码来计算 3+(-2),如下: 最高位的1 发生上溢出,... -
从二进制补码到十进制补码及其内的运算——关于补码的一点学习
2019-01-30 14:02:09从二进制补码到十进制补码及其内的运算——关于补码的一点学习 -
Quartus计算机组成与设计实验原理图整理(十)——二进制补码加法器实验
2021-01-16 18:10:01二、实验方案: 本实验运算器模型,可分为数据运算以及符号位的产生两部分。 三、实验要求: ◆ 数据宽度为4位,设计出实验线路图。 ◆ 设计试验步骤。 ◆ 使用开关进行数据加载,完成补码加、减运算。 ◆ 符号位... -
进制转换小技巧之让你重新认识二进制补码(大师,我悟了)!!!
2020-09-17 19:43:18如果知道二进制补码、十六进制或十进制其中一个,需要转换出其它形式,那么也是很简单的。 对于二进制和十六进制直接转换(技巧在于记住1~15的二进制、十六进制转换关系表,熟练于心) 对于无符号数(正数)来说...