原码,反码,补码的学习

最早呢,我只是简单的认为在计算机中的数值都是二进制进行存储的,而且计算机是逻辑电路,计算机只认识0和1。而且计算机中的二进制都是以补码的形式存在的。

举个例子:按照一个8bit位来说,十进制数5,转换成二进制我们知道是:0000 0101,这个数只是二进制的原码,计算机真正存储的二进制并不是它的原码形式,而是以二进制的补码形式来存储的。(只不过正数5的原反补码都相同)

可是计算机中二进制还对应了有:原码,反码,补码这三种形式,这时我产生了疑问:

原码,反码,补码都是什么 ???

通俗来讲,这三个码就是为了表示数值的,同样也是二进制的三种不同表现形式

举个例子:我们知道5在计算机中以二进制的补码进行存储的,也就是0000 0101 ,这个二进制数呢其实是补码形式,因为举例的这个5是正数,课本上规定的是:正数的原码,反码,补码都是相同的,所以在参与计算时,正数的二进制可以近似的说它们就没有原反补一说,这三个码之间,不管转成哪一个都是一样的,也就没必要区分了。

它们之间有什么关系,怎么转换呢 ???

C语言中 char 5 对应的原码,反码,补码:

                原码:0000 0101

                反码:0000 0101

                补码:0000 0101

char 5 占一个字节(8位),原码最高位是符号位:0代表正,1代表负

C语言中 char -5 对应的原码,反码,补码:

                原码:1000 0101

                反码:1111 1010

                补码:1111 1011

负数的二进制最高位(符号位)为:1

反码:原码的符号位不变,剩余数值位全部取反

补码:反码+1

-5在计算机中的表示形式就是补码形式:1111 1011

为什么计算机中要使用二进制的补码形式进行存储 ???

回答是:

我们设想一下,如果没有补码的话,计算机中的运算会出现加减法,而补码呢就是将负数巧妙的替换成了补码(负数的补码是个正数)因此在计算机中都是以 正数和0的形式存在的,我既然可以把负数变成正数,岂不是所有的减法操作我都可以设计为加法操作(3-3=3+(-3)补)这样我只要在计算机cpu中仅仅设计一个加法器,就可以实现所有的数值运算了,还节约了成本,岂不美哉

举个例子:5-5

这个我们可以直接秒答结果是0,但是在计算机中,由于它只能做加法。

5 - 5 5 + (-5) 补

我们找到这个负数对应的补码之后就可以进行加法运算了,A-B = A+(-B)=A+C,

这里的+C就相当于是-B的补码,也就是说我们找到了这个负数(-B)的替代物(+C),是一个正数,用来代替负数进行运算的。

我们先来做个实验,先算出来5 和 -5 的二进制对应的原码,反码,补码,之后分别进行一个运算

5:

原码:0000 0101

反码:0000 0101

补码:0000 0101

-5:

原码:1000 0101

反码:1111 1010

补码:1111 1011

模拟用原码计算:(假设计算机中以原码形式存在的)(×)

        0000 0101

+     

        1000 0101

       ---------------

        1000 1010

原码表示的:1000 1010对应的十进制是反正不是0

也就是说用原码进行5-5得到了非0这个结果,这个用原码计算结果明显是错误的!!!因此,排除了计算机中用原码形式进行存储以及运算。

模拟用反码计算:(假设计算机中以反码形式存在的)(×)

        0000 0101

+

        1111 1010

        --------------

        1111 1111

得到的反码是:1111 1111

转换成原码是:1000 0000

原码表示的:1000 0000 对应的十进制也不是0,(为啥不是-0,因为这本来就是假设计算机中以反码形式存在的,所以就是个假设,此处有没有符号位一说谁都不知道没人研究过,因此我也不能下定论说这个结果是:-0还是128还是-128。。。。。)

也就是说用反码进行5-5的结果也不是0。因此排除计算机中使用反码进行存储,因为不准确。

模拟用补码计算:(假设计算机中以补码形式存在的)( √ 

        0000 0101

+

        1111 1011

        --------------

     1 0000 0000 (溢出)

        --------------

1溢出,补码结果:变成0000 0000

我们可以看出不仅仅得到了正确的结果0,而且还能唯一的表示0这个数值,因此计算机用补码二进制进行存储运算 !!!

上面我们知道了计算机为什么要使用补码进行存储和运算,因为它能够唯一表示0这个数,而且不会出现计算错误


我们使用补码运算发现,哪里体现了将一个负数替换成了一个正数(补数/补码),来进行加法运算?-5的补码:1111 1011为什么代表正数?

就来解释一下:

负数的补码为什么是正数呢?

我们来用时钟举例子:(补码的原理类似这个时钟,具有周期性,循环性)

假如现在是3点,我想要快速到12点钟,有很多种方法

第一种就是:将时针绕逆时针方向转动三格(-3)到达12点

第二种是:时针绕顺时针方向转动9格(+9),到达12点

通过这两种方法,我们可以发现3-3 和 3+9都可以得到想要的结果

也就是说:3-3 = 3+(-3)= 3+9:成功的把一个减法运算给变成了加法运算,并且将一个负数(-3)成功替换成了正数(+9),得到了一样的结果。而这个+9 就是-3的补数。

上面就是数值在计算机中进行的一系列变化操作,上面也解释了补码为什么都是正数了,既然计算机中只存正数和0,也就没有负数这个说法,也可以理解成计算机中就没有符号位这个说法!!!!(也就是没有所谓的unsigned),全部理解为:都是数值位!!!!! 11111111对应十进制该是多少就是多少,它就是255,它在计算机中就是个补码!!!只是说这个255是计算机中某个负数的补数。这个负数就是-1。计算机中把11111111这个数就当成-1进行计算了。255这个正数只是我们人的数学理解而已。

(具体计算时,计算机根据溢出特性:因此1-1和1+255的计算就有了区分)

那么补数怎么求出来?

在时钟里面能够表示出来的整个范围我们知道是:1 ~ 12 ,也就是一共可以表示12个数,那么这个12就是周期数,每到达12就是一轮(因为12再加1就变成1了),这个周期数就是能够表示范围中最大的数12

因此(-3)补 = 周期数 + 这个负数

                      = 12 +(-3)

                      = 9

其实这个公式说白了就是:

整个面积就是周期数,最大值。

第一种走法就是:红色部分就是-3

第二种走法就是剩余的蓝色部分就是整个面积 - 红色面积 = 12-3 = 9

补数就是蓝色部分,蓝色部分代替了红色部分而已,进而将负数找到了一个正数来代替:也就是-3被替换成了+9

所以我们设想一下,一个正数他的补数是多少?不就是:周期数+正数,那不还是这个正数本身吗。。。。。3+12=3(想象时钟转了一整圈又回到最初的位置了)

而计算机中补码也是这样的原理,就像一个时钟,有周期性的,当达到了最大值时,哪怕就再多1,就又回到了起点。

书上的定义虽然是:原码,符号位不变,其余数值位取反得出反码,最后反码+1,这个有点深奥,不太好理解为什么这样子,可能就是计算机大佬设计或者规定的吧。。。。。

我们知道计算机中只有加法器,做加法,也就是计算机中所有的运算都是加法运算,一个负数在计算机中是按照补码的形式进行运算的,也就是说所有的负数只来到了计算机这个世界都变成了正数(补码)。

前面时钟例子可以知道:所有的负数都可以找到与之对应的补码(正数)/补数(正数)进行替换,来做加法运算操作。

而这个补码是个正数,正数的原码,反码,补码这三种形式都是相同的,那这个二进制对应的原反补就不需区分了呀,反正在计算机中都是以正数补码形式存在,那不就是一堆正数之间加加加加加吗,没有负数,何来的减法操作? 就比如:128在计算机中直接用10000000表示,-128在计算机中也是用补码形式表示的,也是10000000,

疑问来了,为啥-128和+128的二进制补码一摸一样,都是10000000呢?

解释:我们继续看上面这个时钟:它的范围1~12:可以最多表示12个数,周期数为:12,那么-3的补数就是:周期+负数=12+(-3)= +9,所以-3的补数是+9

所以8bit位表示的范围是:00000000~11111111也就是:无论有没有所谓的符号位,都是能一共表示256个数,(-128-127)/(0-255),所以周期是256(想象就是一个钟表,一共256个刻度格,一整圈就是256格)因此-128的补码就是:256+(-128)等于+128,也就是无符号位的 10000000,所以他两个二进制补码是一样的!!!!!

将负数用补码表示,实际上是实现了一种从[-128, 127]到[0, 255](非负数)的映射

而且原码和反码都有符号位,最高位符号位占据一位,那剩下的七位数值,根本无法完整的表示128和-128,因此计算机中才不考虑使用原码和反码进行存储计算!

这不就说一个负数我想知道它对应的补码根本不用什么原反+1补码,换来换去,直接根据补码的特性,直接可找到对应的补数 /补码了。


char 类型:-93的二进制是多少?

char类型占1个字节,八位:00000000~11111111:范围:0~255,周期数:256

-93(补)=256+(-93)=163

163是个正数,对应二进制是:1010 0011,所以-93的二进制是1010 0011(补码形式)

总范围是:0~255,也就是说一共256个数,能表示所有的正负整数。

0-255既然可以表示所有的正负数,因此各分一半(各128个数,128个表示0和正,128个表示负数),0-127代表0和正数,128-255代表负数,我们算出来的这个补码是163,它已经超过了127,正数最大只能表示到127,因此它在后者范围中,163表示的是一个负数,也说明163是某个负数的补数,通过:负数+周期数=补数,负数=补数-周期数=163-256=-93

因此1010 0011 对应的负数是-93,而-93的补数是163

计算机设计将一半表示正数,一半表示负数,比较容易理解的,正数最多能表示到多少?负数最多能表示到多少?

换算一下就知道:

0~127:0-127

128~255:-128~1

(char 范围也就是:-128 ~ 127)


short 表示范围多少呢?能表示多少个整数?

short 占两个字节,也就是16bit,0000 0000 0000 0000 ~ 1111 1111 1111 1111:一共能表示65536个整数。(2^n个,n:位数)

补码表示的正数值范围是0000 0000 0000 0000~0111 1111 1111 1111:0~2^15-1:0~32767

补码表示的负数值范围是1000 0000 0000 0000~1111 1111 1111 1111:2^15~2^16:32768~65535(虽然补码为正整数,但是此范围中代表的都是负整数):表示-32,768~-1

也就是:-32768~32767

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值