原码反码补码移码的目的

不涉及定点、浮点运算。范围仅在整数的数据表示里。

使用比喻,使用相似的思维就可理解其共性,这篇我就想这么写。
计算方法是设计出来的,方法因为什么要这样设计的思维和目的才是我们学习时的主线。
唐朔飞那本教材太高估我的智商,上来就是小数的,补码的全是抽象的计算,都不给几个例子(这,给初学者的教材?)……


我们先用8位二进制数来表示数值

真值 原码 补码(负数时,反码+1) 反码(负数时,原码除了符号位都取反) 移码 (补码符号位抄取反)
-5 1,000 0101 1,111 1011 1,111 1010 0,111 1011
+5 0,000 0101 0,000 0101 0,000 0101 1,000 0101

注意,“逗号”用于区分符号位和其他位,实际并不存在。


明确提出几个需要解决的问题

1.符号位会参与运算
2.所有减法运算都需要变成加法
3.有限的存储位数

解决问题1的原理——映射
人为规定从[-128, 127]到[0, 255]的映射,就可以"仅用正数表示负数"
再规定一个易于直接比较大小的映射(移码)便于比较大小。

解决问题2、3的原理——取模运算
取模后是“补”,加上映射后就对应了相应的正负数
取模本身就是一种位数限制

类似于角度数,
在同圆内60°= -300°,取模运算,此处模是360.(整数范围内,从0到359,按照360=0算)
在一字节8位内中除了符号位的7位,
1111 1111=0000 0000,取模运算,此处模是1 0000 0000(没有超过这个模的数,十进制下你见过某位是十的吗?)

再放一个表格对比悟一下

原码表示的真值(无符号位) 原码表示的真值(有符号位) 补码表示的真值(谁取反+1后是“码”)
1111 1111 255 -127 原码1000 0001,表示-1

设计这种表示方式的目的(遇到问题,发明工具,解决问题)

真值

给出一个数
3(十进制)——真值

无符号二进制数

将3(十进制)表示为二进制
0011——无符号二进制数

扫描二维码关注公众号,回复: 12264553 查看本文章

原码

但是要考虑正负号怎么办?取最高位为符号位!
0,011——原码
啊哈,那么负3(十进制)就是
1,011——原码

补码

我想算5(十进制)-3(十进制)怎么办?
0,101
1,011
这两个数无法直接进行操作得结果!!
给一个映射,正数仍是它本身,负数取模!让负数加上它的取模的值等于1 0000!——实现从[-8,7]到[0, 15]的映射
(模是比最高位大一位的,如十进制的模是10,没有单个位能大于等于10)

补码(为什么按位取反再加一)
我喜欢博主的这句话——“因为你想要的,不是1+1=2,而是,1+1为什么等于2。当然,我们不讨论1+1的问题。我们讨论的,是补码。”
这篇博客总结一下就是【正数+(反码+1)=0 即 负数=(反码+1)】
——按着这么想,正数的映射它本身,负数先所有位取反(包括符号位)
那么比如0010(+2)的反码是1101,相加由于每位都是反,结果为1111,
为了让正数与负数相加“成为0”,就可以再加1成为1 0000,取模为0000,即“相反数相加为零”

于是得-3(十进制)的以1 0000为模的值=1 0000-1011=0 0101
0,101
符号位再按照负的来【1 0000=1111 +1,就可以看成“取反+1”】
1,101——补码

6(十进制)-3(十进制)就可以是
0,110
1,101
求和就是10011,再对1 0000取模就是 0011(是个正补码,正补码等于原码)。
0,011——计算结果的原码(+3)

1(十进制)-3(十进制)就可以是
0,001
1,101
求和就是1110,再对1 0000取模就是 1110(是个负补码)。【补码计算后的仍是补码10011,得结果原码是负数时需要“减一取反”】
对1110“减一”可得1101,再“取反”可得1,010
1,010——计算结果的原码(-2)

移码

在原码比较时
0,011(+3)
1,010(-2)
表示成无符号二进制数时
0011(3)
1010(10)
显然是不合常理的
鉴于边界值都规定好了,可以确定1打头的都是负数、0打头的都是整数——换一下不就好了??
1011—— +3的移码
0010—— -2的移码
这样,原码在无符号二进制数的映射就是合理的了


养料:

摘自:原码、反码、补码的产生、应用以及优缺点有哪些?——何新宇
补码来历的描述,可以总结如下:
1.计算机里面,只有加法器,没有减法器,所有的减法运算,都必须用加法进行
2.用补数代替原数,可把减法转变为加法。
3.出现的进位就是模,此时的进位,就应该忽略不计。
4.二进制下,有多少位数参加运算,模就是在 1 的后面加上多少个 0。
补码就是按照这个要求来定义的:正数不变,负数即用模减去绝对值。

摘自:原码、反码、补码的产生、应用以及优缺点有哪些?——张天行

所谓原码就是机器数,是加了一位符号位的二进制数,正数符号位为0,负数符号位为1,计算机中存储、处理、运算的数据通常是8位、16位、32位或64位的,这里以最简单的8位为例讲解。注意符号位是包含在8位中的其中1位,故可直观读出的数只有7位(只有后7位数可以按权展开)。有心人可能注意到原码是有缺陷的,它只能表示255种状态,因为00000000(+0)和10000000(-0)其实是一个数,因此原码的表示范围成了-127到+127,这个问题需要神奇的补码来解决,因为在补码中10000000被用来表示-128。
所谓反码,英语里又叫ones’ complement(对1求补),这里的1,本质上是一个有限位计数系统里所能表示出的最大值,在8位二进制里就是11111111,在1位十进制里就是9,在3位十六进制里就是FFF(再大就要进位了)。求反又被称为对一求补,用最大数减去一个数就能得到它的反,很容易看出在二进制里11111111减去任何数结果都是把这个数按位取反,0变1,1变零,所以才称之为反码。用原码求反码的方法是,正数不变,负数保留符号位1不变,剩下位按位取反。
所谓补码,英语里又叫two’s complement(对2求补),这个2指的是计数系统的容量(模),就是计数系统所能表示的状态数。对1位二进制数来说只有0和1两种状态,所以模是10也就是十进制的2,对7位二进制数来说就是10000000,这个模是不可能取到的,因为位数多一位。用模减去一个数(无符号部分)就能得到这个数的补,比如10000000-1010010=0101110,事实上因为10000000=1111111+1,稍加改变就成了(1111111-1010010)+1,所以又可以表述为先求反再加1。总结求补码的方法就是正数依旧不变,负数保留符号位不变,先求反码再加上1。
记住了怎么求补码,接下来讲讲运算。通过原码的符号位和数值,我们能迅速指出它代表的数,判断其正负并进行四则运算,相比而言反码和补码对于人则显得过于晦涩。如果说原码是给人看的数字语言,那么补码就是计算机的数字语言。计算机不需要知道什么是正负、大小,这些判断对它而言过于复杂。事实上它存储、处理、传输的数都只有补码一种形式,人所做的加减乘除,在计算机里只通过相加和移位就能解决,这都来自于补码系统的内在自洽和巧夺天工的神奇魔力,也是后文要阐述的重点。
对加法和减法,按上文的方法求得补码之后,直接相加就可以了,但相加的时候符号位一定要一起参与运算,有时候,两符号位相加或者接受来自低位的进位会发生溢出,就扔掉溢出的一位(稍后会解释为什么),由新的符号位决定结果的正负,如果是0表示正数,结果就是原码,如果是1表示负数,结果还要再求补数得到原码。

摘自:补码对应128
将负数用补码表示,实际上是实现了一种从[-128, 127]到[0, 255]的映射。如下所示:

+----------------------------+
| 255     -1       11111111  |
| 254     -2       11111110  |
| 246     -10      11110110  |
| 156     -100     10011100  |
| 129     -127     10000001  |
| 128     -128     10000000  |
| 127      127     01111111  |
| 100      100     01100100  |
| 10       10      00001010  |
| 2        2       00000010  |
| 1        1       00000001  |
| 0        0       00000000  |
+----------------------------+

猜你喜欢

转载自blog.csdn.net/sinat_27382047/article/details/105916458