美文网首页
原码、反码、补码的分析,为啥正数的反码和原码相同,负数的反码等于

原码、反码、补码的分析,为啥正数的反码和原码相同,负数的反码等于

作者: 黑色蚂蚁_MGL | 来源:发表于2019-09-22 09:24 被阅读0次

之前学习的原码、反码、补码之间的转换,都是课本上教的,但是不知道为啥要那么转换,最近在看《编码》这本书,讲到加法器的实现,又看到了补码,就决定把这几个的关系研究研究

以下故事纯属虚构,为了直观简单所有运算都是按照4bit运算来讲解,4bit最多表示16个数,0~15 或者-8~7 所以别越界哦,下面开始讲故事 ~

很早以前有个路人甲发明了二进制,逢二进一,3就用(0011=0*2³ + 0*2² + 1*2¹ + 1*2º)表示,2就用(0010=0*2³ + 0*2² + 1*2¹ + 0*2º)来表示,那么负3和负2用啥来表示呢,突然想到手写的10进制中,负数是在前面加一条横杠比如-6、-2,所以想二进制也用加一条"横杠"来表示负数吧,所以在最左边是1(横杠)的就是负数,不是1的就是正数。

后来发明了计算机,由于计算机实现加法运算还算容易,实现减法非常复杂(会在另一篇文章讲解加法器),所以就只有加法器,那么减法运算只能转化成加法,减一个数等于加一个数的负数,然后计算机就用路人甲发明的表示负数的方法进行运算

(1) 2+3 = 0010 + 0011 = 0101 = 5      俩正数相加还是不错的 ~

(2) 3-2 = 3 + (-2) = 0011 + 1010 = 1101 = -5    what?咋是-5 ,仔细看发现,只要是一个正数一个负数相加,最左边肯定是1,那就肯定是负数了 ,不合理

(3) 2-3 = 2 + (-3) = 0010 + 1011 = 1101 = -5  what? 同上 ~

(4) -2 -3 = -2 + (-3) = 1010 +1011 = 0101 = 10101 因为符号位相加导致溢出,最高位溢出结果为0101 = 5 

(5) 0 + 0 = 0000 + 0000 = 0,   0 - 0 = 0  + (-0) = 0000 + 1000 = 1000 = -0, -0 - 0 = -0 + (-0) = 1000 + 1000 = 0000 = +0    运算没错,只是有正负0而已

从上面可以看出,符号位参与运算是有很大问题的,导致运算结果不对,那么怎么才能不让符号位进行运算呢 ~ 很简单,路人乙想到了一个号方法

反码要产生了

路人乙想 :符号位的产生,就是为了表示负数的,如果我表示负数的时候不用符号位,用另一种方式,是不是可以呢,结果就想到了用相反数表示负数,比如3 = 0011,因为二进制非0即1,所以-3可以将3(0011)按位取反得到1100,用1100表示-3,啊呀,这样不就没有符号位了。“反码”就产生了,用相反数表示负数的编码方式叫反码,那路人甲原来发明的编码方式就叫负数的"值"等于正数的"值"所以叫原码,(但是这种表示方式在读取负数的值的时候是不方便的,比如给你个1100,你必须得转换成他对应的正数0011(3),才知道是0011的反码,是"负0011"(-3))

那原码和反码啥关系呢 原码表示3用0011 反码表示3也用0011 ,所以正数的原码等于反码,原码表示-3用1011,反码表示-3是1100  所以负数的反码等于原码非符号位取反


这是百度百科对反码的解释,不要把反码和相反数弄混了,反码专门就是给咱们程序员造的词 ~

接下来咱们看看没有符号位的反码进行运算,结果会怎么样呢, 注意结果也是反码,下面已经没有符号位这一说了

(1) 2+3 = 0010 + 0011 = 0101 = 5      正数和原码一样,所以结果也是对的

(2) 3-2 =  0011 - 0010 = 3 + (-2) =  0011 +1101 = 10000 最高位溢出结果为0000 = 0,应该是1结果是0 

(3) 2-3 = 0010 - 0011 = 2 + (-3) = 0010 + 1100 = 1110(反码,是一个负数) = -0001(转成正数) = -1 可以

(4) -2 -3 =  -2 + (-3) = 1101 +1100  = 11001 最高位溢出后是1001 = -6 应该是-6结果少了1变成-6了

(5) 0 + 0 = 0000 + 0000 = 0000 = +0

      0 - 0 = 0  + (-0) = 0000 + 1111 = 1111 = -0,

     -0 - 0 = -0 + (-0) = 1111 + 1111 = 1 1110 = 1110 这个不对了,不管是+0还是-0都不是

仔细观察可以发现以下规律

(1) 正数 + 正数 = 正数 ----没问题

(2) 正数 + 负数 = 正数------结果少1

(3) 负数 + 正数 = 负数-----没问题

(4) 负数 + 负数 = 负数------结果少1

(5) -0 + -0 是不对的 -----结果多1

补码要产生了

眼看路人乙的想法也行不通,路人丙看到上面的规律(1)发现全是正数加是没问题的,从(2)可以看出,如果负数的表现形式在之前反码的表现形式上再补个1,那么(2)就没问题了,结果发现(4)也变得没问题了。因为是是补了个1得来的,那就叫补码吧 ~ 下面咱们来运算一下看看

公式由之前的 (负数 = 正数各位取反)  ---->  (负数 = 正数各位取反 + 1)

(1) 2+3 = 0010 + 0011 = 0101 = 5      正数 + 正数是和反码没区别的,所以没问题

(2) 3-2 =  0011 - 0010 = 3 + (-2) =  0011 +(1101 + 1) = 0011 +1110 = 10001 最高位溢出结果为0001 = 1

(3) 2-3 = 0010 - 0011 = 2 + (-3) = 0010 + (1100 +1)  =  0010 + 1101 = 1111  补码运算,得到的也是补码,那这个补码是个负数,对应的值是多少呢,根据公式 (负数 = 正数各位取反 + 1) 则1111-1 = 1110 再取反 是0001  = 1,所以1111是正1的补数,那就是负一

(4)-2 -3 =  -2 + (-3) =(1101 + 1) + (1100 + 1) = 11011 = 最高位溢出后是1011 对应的正数是                                    5((0101)),所以是5的补码,那就是负5

哇,运算的问题终于解决了,但是补码只是用来运算的,他的负数表示太不直观,所以最终定的是,二进制的正负数还是用原码表示(直观,咱们开发者变成的时候还是用原码便是),但是运算的时候用补码运算(数值在计算中就是用反码存的,运算也是用反码)

补充

上面补码的产生说的是根据反码,找出来的规律 ~这是我自己编的。。。。。,但是补码运算确实是没问题的

下面说说正经的,为啥叫补码呢,可能就是有点互补的意思的,A+B = 固定的数。A和B是互补的。从搜索的资料来看,大部分说的是根据“模”时钟启发来的。比如时钟一共12个数,1到12点,那么2+10 = 12、4+8=12,那2和10,4和8都是互补的。比如现在指针指向12点,想让时钟指到 1点,可以顺时针+1 也可以逆时针 减11 ,也就是 -(12-1)。想让时钟指向10点,可以逆时针 -2 也可以顺势针 +10。结论就是

顺势针拨的数(也就是绝对值) + 逆时针拨的数(也就是绝对值) = 总的个数,两个数还是对于12说是互补

听起来有那么点道理,但是现在是中午十二点,我顺势针+1是下午1点,逆时针-11是凌晨1点,位置是一样,可他妈时间不一样啊 ~ 带着疑问运算一把看看,咱们就只运算那两个之前有问题的(2)和(3),首先咱们举例都是4bit进行运算的也就是 内存占用是这样的 

口口口口 

四个格子,能表示的数是2的4次方 = 16也就是0-15,再注意一点就是用这种方式代替负数就是不想有符号位,所以下面的运算中所有的数最高位不代表符号,是数值位

(2) 3-2 = 3 + (16 -2) = 3 + 14 = 0011 + 1110 = 10001 去掉溢出的最高位是0001 = 1

(4)-2 -3 = (16 - 2) + (16 - 3) = 14 + 13 = 1110 + 1101 = 11011 = 最高位溢出 1011 是11

啊呀,一看用"模"运算也不对啊 ~到底咋回事 ~ 突然想到我的疑问,下午一点和凌晨一点能一样吗? 答案是 不一样 !

接下来继续讲解怎么就对了

把上面的(2)(4)再说一下

(2) 3-2 = 3 + (16 -2) = 3 + 14 = 0011 + 1110 = 10001 去掉溢出的最高位是0001 = 1,咱们本来是-2结果变成了+14,虽然位置一样,但是多转了一圈啊。咱们再看右边 10001,溢出以后咱们把最高位丢弃了,只剩0001,那么丢弃的最高位代表的就是16,就是一圈啊,等号左边多加了一圈,右边减了一圈,所以没毛病 ~按照上面的公式  3-2 = 0011 + 1110 = 10001,那-2可以用1110代替,那-2就是2(0010)取反加一

(4)-2 -3 = (16 - 2) + (16 - 3) = 14 + 13 = 1110 + 1101 = 11011 = 最高位溢出 1011 是11(在这没符号位这一说)

那这个怎么解释呢?

左边多了两圈,右边溢出一个,少了一圈,那右边还有多的一圈,说明1011还是多了一圈的,所以虽然结果是1011(11),但是他是多了16的,所以实际应该是-5,1011代表的-5也就是正5取反 + 1

(5) -0 - 0 = -0 + (-0) = (16 -0) + (16 -0) = (1111 + 0001)  + (1111 + 0001) =  1111 + 1111 + 0001 + 0001 =  1110 + 0010 =   1 0000 去掉最高位后是0000 是0,但是根据上面说的,0000应该还得减去一圈那就是0000代表的是-16

仅仅是表示而已,比如一个字节是8位,如果有符号的话表示-128 ~ 127 但是你用过-128 吗

总结一下:

(1)原码、反码、补码,是互相独立的,不存在依赖关系,只是之间的表示方法存在规律

(2)原码、反码、补码都是针对负数怎么表示研究出来的。正数的表示方法都是统一的,负数的数值和正数的数值表示方法一样的方式就是原码、负数是正数各位取反的表示方式就叫反码、负数是正数各位取反再补上个1的表示方式就叫补码

(3)原码的形式可以很直观的表示出负数,所以在书面书写时,一般用原码,比如编程,但是因为计算问题,计算机存储的时候都是存储的补码,计算机只管存储,计算,不在意是否是正数,负数。正负是由编译器和操作系统自己的规则决定的。

相关文章

  • 原码、反码和补码

    正数的原码、反码和补码相同,亦是正数 负数的原码、反码和补码符号位为1,代表负数,反码在原码的基础上符号位不变,其...

  • 按位异或运算 (正数异或负数) 、按位非(~)

    正数反码:与原码相同 负数反码:符号位为“1”,数值位按位 取反。 正数补码:与原码相同 负数补码:求反加一 记住...

  • 软件测评师做题技巧

    第一类补码,反码,原码 正数:原码=反码;补码=原码负数:反码=原码求反;补码=反码+1 第二类用例概率的计算 测...

  • 2018-10-22 Python31 原码、反码、补码

    原码、反码、补码 1)如何计算补码?规则: 正数:原码 = 反码 = 补码负数:反码 = 符号位不变,其他位取反补...

  • 位运算

    原码,反码,补码 原码 正数的原码就是其二进制本身 负数的原码是把对应的正数的原码最高位改为1 反码 正数的反码就...

  • 进制关系

    各进制的形式 正数的原码、反码、补码相同 负数的反码为原码各位取反,补码为反码+1 计算机的底层都是以补码的方式来...

  • 原码 反码 补码

    原码:带符号位的,我们表示的数值 反码:正数的反码是原码,负数的反码是除了符号位之外其余位取反 补码:正数的补码是...

  • java中二进制、八进制、十进制、十六进制的转换

    运行结果: 然后简单总结一下原码、反码和补码:正数:原码、反码和补码都相同负数:原码:第一位为符号位,后面是数字位...

  • 位运算

    1.原码、反码、 补码正数的原码、反码、 补码都一样 正数以原码存储在计算机负数 以补码存储在计算机 例...

  • 原码、补码、反码

    正数的原码补码反码都相同,如: 3的原码:00000000 00000011 反码:00000000 000...

网友评论

      本文标题:原码、反码、补码的分析,为啥正数的反码和原码相同,负数的反码等于

      本文链接:https://www.haomeiwen.com/subject/vpjqjctx.html