从原码,反码,补码的设计理念来深刻理解其原理

2021年11月20日 阅读数:2
这篇文章主要向大家介绍从原码,反码,补码的设计理念来深刻理解其原理,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

原码,反码,补码你们都知道,下面经过解析为何当初要这样设计,让你更透彻的理解它们的原理。html

文章参考:编程

https://blog.csdn.net/afsvsv/article/details/94553228
https://blog.csdn.net/wu_nan_nan/article/details/54633506
https://www.zhihu.com/question/28685048
原文:https://blog.vchar.top/base/1611834985.html框架

计算方式

原码:是计算机机器数中最简单的一种形式,数值位就是真值的绝对值,即二进制表示的格式;其中最高位是符号位,符号位中0表示正数,1表示负数。.net

反码:正数的反码和原码同样;负数的反码是它原码除符号位外,其余位按位取反。设计

补码:正数的补码和原码同样;负数的补码等于它反码+1,或者说是等于它的原码自低位向高位,尾数的第一个‘1’及其右边的‘0’保持不变,左边的各位按位取反,符号位不变。code

为何这样要计算呢?

因为计算机的硬件设计决定,其本质都是以二进制码来存储和运算的;根据冯~诺依曼提出的经典计算机体系结构框架。一台计算机由运算器,控制器,存储器,输入和输出设备组成。其中运算器,只有加法运算器,没有减法运算器(听说一开始是有的,后来因为减法器硬件开销太大,被废了 )。htm

所以在计算机中是没有减法的,只有加法运算。即减一个数至关于加上一个负数。blog

因此须要设计一种新的计算规则来实现计算机的加法运算;注意咱们须要的是一个新的规则来适配计算机的加法运算,使其最终结果和咱们现有的计算规则的结果同样!!get

下面咱们以4位的二进制数为例作设计。数学

原码

原码:是最简单的机器数表示法。用最高位表示符号位,‘1’表示负号,‘0’表示正号。其余位存放该数的二进制的绝对值。

下面这个以原码的规则计算机中存储的数据

/ 正数 / 负数
0 0000 -0 1000
1 0001 -1 1001
2 0010 -2 1010
3 0011 -3 1011
4 0100 -4 1100
5 0101 -5 1101
6 0110 -6 1110
7 0111 -7 1111

这种设计方式很简单,虽然出现了-0和+0,可是还能接受;下面咱们开始作运算:

	0001+0010=0011  ==>> 1+2=3      没得问题
	0000+1000=1000  ==>> 0+(-0)=-0  能够接受
	0001+1001=1010  ==>> 1+(-1)=-2  哦,这个...

这种方式在正数之间进行没得问题,可是有负数的运算就不行了,看来原码干不了这个活啊;因而反码来了。

反码

咱们知道,在十进制中一个数和其相反数相加等于0,对应的减法也可定义为一个数加上另外一个数的相反数;基于这一点反码的设计思路出来,那就是定义二进制的相反数求法。

直接按十进制的套用明显不行,那么让它的原码除符号位外,按位取反;因为正数使用原码进行计算没得问题,就暂时不动它,只让其适用于负数。获得以下的结果:

如今再来计算:

	0001+1110=1111  ==>> 1+(-1)=-0  如今正确了

注意如今计算机中实际存储的是反码了。

	1110+1101=1011  ==>> -1+(-2)=--4  哦,这个...

这种方式好像在计算负数+负数的时候不得行啊。

不过咱们已经解决了相反数相加的问题了,对于负数咱们直接让其符号位固定为1便可达到正确结果。

0001+1110=1111 ==>> 1+(-1)=-0  这个看着怪别扭的

这种负0看着怪别扭的,同时须要在负数+负数的时候还要作个符号位强制位1的操做,太麻烦了,要想个办法偷懒(平时编程中也应当有个偷懒的思惟 hhh); 因而补码出现了。

补码

因为正数是没得问题的,不作修改,因此正数的补码等于他的原码;负数的补码等于反码+1。(这只是一种算补码的方式,多数书对于补码就是这句话)

负数的补码等于他的原码自低位向高位,尾数的第一个‘1’及其右边的‘0’保持不变,左边的各位按位取反,符号位不变。

想一想当年那些计算机学家(高级专业偷懒户),并不会心血来潮的把反码+1就定义为补码。下面来看看其设计缘由。

因为使用十进制的计算方式已经不能知足二进制的需求了,所以咱们须要跳出来,从新找灵感。

生活中的时钟有12个刻度,若是时针如今在10点的位置,那么何时会中止在8点钟的位置呢?

这个很简单再过10个小时,或者2个小时前,那么获得以下公式:

10-2=8=10+10 时间超过12就会从新开始,这种称为模。

在时钟运算中,减去一个数,其实就至关于加上另一个数(这个数与减数相加正好等于12,也称为同余数)

经过时钟的例子能够发现最终转换后的计算表达式是2个正数相加,而从前面的结论中2个正数进行运算其符号位并非必须的,那么如今设计补码时咱们暂时就将符号位去掉。

这也是为何正数的符号位是0,负数的符号位是1的缘由;由于若是正数的符号位是1的话,因为其符号位被忽略,当其参与运算时就会发生进位的状况,而使用0就不会有这种状况。

  • 同余数

如今就是须要求这个同余数的问题,根据数学中对同余数的定义:

    两个整数a,b,若它们除以整数m所得的余数相等,则称a,b对于模m同余。

例如,当m=12时,3跟15是同余的,由于3mod12=3=15mod12,对于同余,有以下结论:

    a,b是关于m同余的,当且仅当,两者相差m的整数倍,
    a−b=k×m, with k=……−2,−1,0,1,2,……
    即,
    a=b+k×m, with k=……−2,−1,0,1,2,……
    一个数x加a对m取余,等于x加a的同余b对m取余,即,
    (x+a) mod m=(x+b) mod m.
    由1.易知2.是成立的。

将参数带入:

    3-15=-1*12  === 3=15+(-1)*12
    (x+3)%12=(x+15)%12

将上面的表达式在简化下:

    若:a=b+m,则 (x+a) mod m = (x+b) mod m

那么如今该如何来求这个同余数呢?也就是找到负数补码的求法。

若b为一个负数,表达式能够转为相似以下:

a-b=m  ===>> 设c=-b,则:a+c=m

如今要 求a;经过上面的推导,咱们在运算时能够减法转换为加法,至关于将负数转换为了正数,那么符合位也就没有用了;所以咱们新设计的补码就能够不要符合位(由于都是正数的运算了)。

参考时钟的案例,咱们最终其实只关注二进制位数可以表示的数(由于多余的位数也没地方存储),即时钟刻度的最大值就是m,也就是二进制位数表达的最大值,例如4位的最大值就是16。

因此求a即计算m-c就是求其二进制的另外一半。而c的另外一半就是把二进制位上的0变一、1变0即取反,它们相加后全是1,而m是其最大值+1,所以还须要加1才行。而这就是补码的求法。这个计算的方法还能够参考时钟的状况。下面来实际计算验证一下:

示例1:

    3-5=-2=(3+11)%16
    
    0011(3的补码) + 1011(-5的补码,11的原码) = 1110
    1110是一个补码(此时最高位就是符号位)转为原码:1010 即为-2

示例2:

    5-3=2=(5+13)%16
    
    0101(5的补码) + 1101(-3的补码,13的原码) = 1 0010
    因为总共只有4位,产生的进位会被丢掉,所以最终的补码为 0010 转为原码:0010即为2

示例3:

0001+1111=1 0000 ==>> 1+(-1)=0  这样以前的-0问题也解决了

最终使用补码知足了咱们的要求,所以在计算机中实际存储的是补码,进行操做的时候也是经过补码来进行操做。