目录
一、原码反码补码
原码
第一位表示符号, 其余位表示值.
反码
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余位都取反.
补码
正数的补码就是其本身
负数的补码是 在反码的基础上+1
+1 = [00000001] 原
= [00000001] 反
= [00000001] 补
-1 = [10000001] 原
= [11111110] 反
= [11111111] 补
对于正数三种编码方式的结果都相同
二、别人对于补码的探索
以下原码反码补码的内容大幅度转载于此篇文章:但是也有一些错误的地方
https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html#!comments
对于负数:虽然人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减.
但是对于计算机, 加减乘数这些最基础的运算要设计的尽量简单.
让计算机去辨别"符号位"显然会让计算机的基础电路设计变得十分复杂!
于是人们想出了将符号位也参与运算的方法:
根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.
于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码:
计算十进制的表达式: 1-1=0
1 - 1
= 1 + (-1)
= [00000001]原 + [10000001]原
= [10000010]原
= -2
如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.
为了解决原码做减法的问题, 出现了反码:
计算十进制的表达式: 1-1=0
1 - 1
= 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反 = [1000 0000]原
= -0
结果貌似是对了的。但是发现有[0000 0000]原和[1000 0000]原两个编码能表示0.而最关键的是:
用反码计算减法,只有当结果是负数或0时,结果的真值部分才是正确的,当结果是正数时就不对了:
计算表达式:20 + (-10):
1) 最高位区分正负:-10的二进制数为10001010
二进制计算:00010100 + 10001010 = 10011110
10011110转换成十进制是 -30 !!!
可以理解为:反码不可以直接用作计算
补码的出现, 解决了反码不可以直接用作计算的问题:
1-1
= 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]补 + [1111 1111]补
= [0000 0000]补
= [0000 0000]原
这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:
(-1) + (-127)
= [1000 0001]原 + [1111 1111]原
= [1111 1111]补 + [1000 0001]补
= [1000 0000]补
第1位是符号位始终不会变。所以,当进到第8位的时候,就表示溢出了,会被舍弃
-1-127的结果应该是-128, 在用补码运算的结果中:[1000 0000]补 就表示-128不是-0.
但是注意因为实际上是使用以前的-0的补码来表示-128, 所以 -128并没有原码和反码表示.
对-128的补码 [1000 0000]补 去计算原码 (得到 [0000 0000]原)是不正确的
这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].
对于编程中常用到的32位int类型, 可以表示范围是: [-2^31, 2^31-1]
以上。
虽然有那么一点点的大问题,但是让我想起了一些大学计算机基础课学的知识,感谢!
三、我对补码来源的探索
下面摘来一段上面那篇博客中我觉得很精辟的评论:
对于8位机来说: 最大的无符号数就是2^8-1 有符号数是从 -128 ~ 128 -1
对有符号数的理解:其实就是把 127之后的数字,都用来表示负数了,最高位(第八位)永远是1
机器码 0000 0000 到 0111 1111 | 1000 0000 到 1111 1111
无符号十进制 0 到 127 | 128 到 255
有符号十进制 0 到 127 | -128 到 -1
或许采用补码的原因就只是 给负数找个存放的地方而已.
所谓 负数的原码 取反 再加1, 实际上,就相当于,加一个256,也就是2^8.
比如:上边的 -128 = 128-256, -127=129-256,..., -1=255-256.
呵呵,还说什么把减法转变成加法,扯淡吧(我是说写书的那人),试试1-3,怎么变成加法? 1+(-3) ?那这个补码表示法,有毛关系啊?小学就学了好不.
我觉得这段评论还说的很在理,有灵感!读完以后我自己的一点理解(有可能会误导大家):
- 首先,对于8位机来说,机器码是 从 0000 0000 到 1111 1111
- 如果都用来表示无符号数(即正数)的话,能表示从0到255的正数
但是对于计算机来说,你总不能让他去算对于他来说非常复杂的减法嘛!  ̄へ ̄ 所以想到把减法1-3 变成加法 1+(-3)
但是为什么计算机不去直接计算减法?
1,本质上,计算机只会与/或/非,在它眼中根本没有加减乘除
2,用 与/或/非 逻辑电路构成更复杂一点的 半加器
3,再用 半加器 构成 全加器,实现 带进位的加法
4,再再用 全加器 实现减法/乘法/除法
PS:
(1) 加法器电路是对“人类手工计算加法"的模拟
(2) 理论上,可以用相关逻辑电路来直接模拟人类手工计算减法/乘法/除法,只是相较于前述方法,电路将变得异常复杂~
以上来源于百度知道
看到这个回答我就懵了一哈,半加器?全加器?怎么这么熟悉!难道!难道这是刚考完的电子电路技术中的知识吗!!!
我佛了! 于是我又把刚删除的电子电路的PPT重下了回来:
我艹!电子电路牛逼!!
但是,为什么没有人告诉我电子电路学的东西可以用在这里,为什么?假如老师提前和我讲好,我一定好好看书,
一定不会考前3天速成,敲里吗。我还以为大学学的课程除了编程方面的就没什么用了呢,嘿嘿嘿,mmp。
懒人我,就不重学一遍电子电路了,只想先看看加法器这里的东西:
加法器可以实现二进制数的加法,在加法器上增加一些电路也可以用于减法、乘法和除法
嗯~~~ 考前一下不想看,现在只看了一眼,我就觉得这个电子电路也很有意思嘛!嘿嘿嘿
半加器:两个一位二进制数相加,不考虑进位,则称为半加
Si 表示的是 当前位的运算;
Ci+1 表示的是 向高位的进位;
全加器:在进行多位二进制数相加时,考虑进位,这种二进制加法称为全加
Ci 表示的是 从低位来的进位 ;
Si 表示的是 当前位的运算;
Ci+1 表示的是 向高位的进位;
把N个全加器级联,每个全加器将两个1位二进制数相加,则成为完成两个N位二进制数相加的加法器。
根据进位信号产生方式的不同,加法器有串行进位、并行进位等进位方式
串行进位加法器:在加法运算过程中,进位信号是由低位向高位逐级产生。进位逐级传输,最高位的运算要等待低位的运算完成之后才能进行,故运行速度慢,但电路结构简单。
并行进位加法器:为了提高运算速度,必须减少由于进位引起的时间延迟,方法就是事先求出由两个加数构成的各级加法器所需要的进位,相当于把低位来的进位直接送到高位。
在研究加法器的时候看到有人说计算机里有加法器和移位器,但是为什么不用个减法器啊?而要用加法器算减法?
在某贴吧看到这句话:用加法器可以计算负数减负数等等
突然意识到:其实更大的问题是 如何让计算机进行 负数的加减乘除运算
其实计算机不是非要用加法器去计算减法的:而是在实际运算中,计算机不得不去处理负数,既然计算机可以处理负数,那就必定就可以用 1+(-3) 来代替减法 1-3 了,那还要减法器干什么?既然有现成的加法器可以用来计算减法,还何必再增加一个减法器呢? 所以计算机应该不是嫌减法复杂才用的加法代替减法的,而是负数的强大存在使得计算机可以只使用加法器就能完成加减运算
以上:全都是我自己瞎想的。百分之99都是错的,哈哈哈哈哈哈。。。。
想通了为什么以后,还是返回到正题上:负数的补码探索
以我们原有的数学经验,在10进制中:1 表示正1,而加上负号:-1 表示和1相对的负值。
那么,我们会很容易认为在2进制中(1个字节): 0000 0001 表示正1,则最高位为1后:1000 0001应该表示-1。
然而,事实上计算机中的规定有些相反,请看下表:
二进制值(1字节 = 8位) | 十进制值 |
1000 0000 红色的1代表负数蓝色的是补码(补码=反码+1) | -128 |
1000 0001 蓝色部分代表多大的值?:将补码还原为原码 | -127 想化成负数?:先减去1再按位取反 |
1000 0010 还原方法:补码-1再取反 | -126 |
1000 0011 | -125 |
... | ... |
1111 1110 | -2 |
1111 1111 | -1 |
然后我们有些奇怪地发现,1000 0000 并没有拿来表示 -0;而1000 0001也不是拿来直观地表示-1。
事实上,-1 用1111 1111来表示。怎么理解这个问题呢?先得问一句是-1大还是-2大?
当然,-1是最大的负整数。计算机中无论是字符类型、整数类型、无论这个整数是几个字节。它都用全1来表示 -1。
比如一个字节的数值中:
- 1111 1111表示 -1,那么,1111 1111 - 1 是什么呢?。
- 1111 1111(-1) 减 1 = 1111 1110(-2)。这样的运算才是符合的数学里减法逻辑的
所以,为什么 1000 0000 不是 -0而是-128 、1000 0001 不是 -1 而是-127、为什么全1表示-1 就恍然大悟了吧!
摘抄自:
https://www.cnblogs.com/ASPNET2008/archive/2009/04/29/1446471.html
在瞎琢磨一大通之后,终于找到了一个知乎上大神的回答,完美的解决了我的根本疑惑:补码到底是怎么来的
先转载一波: