在学习原码、补码和补码之前,需要先了解机器数和真值的概念。
1、机器数
一个数在计算机中的二进制表示形式称为该数的机器号。机器编号已签名。在计算机中,数字的最高位用于存储符号。正数为0,负数为1。
例如,十进制数字+3的计算机字长为8位。转换成二进制后为00000011 。如果为-3 ,则为10000011 。
所以,这里的00000011 和10000011 是机器号。
2、真值
由于第一位是符号位,机器号的形式值不等于实际值。例如,上面的有符号数10000011,最高位1代表负数,其实际值为-3,而不是形式上的值131(10000011转换为十进制等于131)。因此,为了区分,将带有符号位的机器号对应的真实值称为机器号的真实值。
示例:0000 0001 的真实值=+000 0001=+1,1000 0001 的真实值=000 0001=1
二. 原码, 反码, 补码的基础概念和计算方法.
在探讨机器为什么使用补码之前,我们先了解一下原码、补码和补码的概念。对于一个数字,计算机必须使用一定的编码方式来存储它。原码、补码和补码是机器用来存储特定数字的编码方法。
1. 原码
原码是符号位加上真值的绝对值,即用第一位表示符号,其余位表示数值。例如,如果是8位二进制:
[+1]原始=0000 0001
[-1]原始=1000 0001
第一位是符号位。因为第一位是符号位,所以8位二进制数的取值范围是:
[1111 1111, 0111 1111]
现在
[-127, 127]
原始代码是人脑最容易理解和计算的表示形式。
2. 反码
的表达式为:
正数的补码是它本身
负数的补码以其原码为基础,符号位不变,其余位取反。
[+1]=[00000001]原值=[00000001]逆值
[-1]=[10000001]原始=[11111110]逆
可见,如果补码代表负数,人脑无法直观地看到它的值。通常需要将其转换为原始代码,然后进行计算。
3. 补码
补码表示为:
正数的补码是它本身
负数的补码在其原码的基础上,符号位不变,其余位取反,最后+1。 (即在补码的基础上+1)
[+1]=[00000001] 原值=[00000001] 逆值=[00000001] 补码
[-1]=[10000001] 原=[11111110] 逆=[11111111] 补
对于负数,人脑无法直观地看到二进制补码表示中的值。通常还需要将其转换为原始代码来计算其值。
三. 为何要使用原码, 反码和补码
在开始深入学习之前,我的学习建议是熟记上面的原代码、补码和补码的表示以及计算方法。
现在我们知道计算机可以用三种编码方法来表示数字。对于正数,三种编码方式的结果是一样的:
[+1]=[00000001] 原值=[00000001] 逆值=[00000001] 补码
所以没必要解释太多。但对于负数:
[-1]=[10000001] 原=[11111110] 逆=[11111111] 补
可以看出,原码、补码和补码是完全不同的。既然原码是直接被人脑识别并用来计算表示的,为什么还存在补码和补码呢?
于是人们开始探索如何让符号位参与运算而只保留加法。首先我们看一下原始代码:
计算十进制表达式: 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
发现用补码进行减法运算时,结果的真值部分是正确的。唯一的问题实际上发生在特殊值“0”上。虽然人们理解+0和-0是相同的,但是0是有符号的,它没有任何意义。此外,还会有两个代码:[0000 0000]和[1000 0000]来表示0。
所以补码的出现解决了0和:这两种编码的符号问题
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-127 的结果应该是-128。在补码运算的结果中,[1000 0000]的补码是-128。但注意,因为前面的-0补码实际上是用来表示-128的,所以-128没有原码和补码表示。 (由-128[1000 0000]的二进制补码表示计算出的原始代码是[0000 0000]原始,这是不正确的)
使用补码不仅解决了0的符号和两个码存在的问题,而且还可以多表示一个最小数。这就是为什么原码或补码表示的8位二进制的范围是[-127, + 127],而用补码表示的范围是[-128, 127]。
因为机器使用的是二进制补码,所以对于编程中常用的32位int类型来说,因为第一位代表的是符号位,所以可以表示的范围是:[-231, 231-1]。当使用二进制补码表示时,多保存一个最小值。
四 原码, 反码, 补码 再深入
计算机巧妙地将符号位参与运算,将减法变成加法。它背后有哪些数学原理?
将时钟视为一位十六进制数。如果当前时间是6点,我想将时间设置为4点,该怎么办?我们可以:
1. 回拨2 小时: 6 - 2=4
2. 向前拨10 小时: (6 + 10) mod 12=4
3. 向前拨10+12=22 小时: (6+22) mod 12=4
2,3法中的mod指的是取模运算,16 mod 12=4,即16除以12后的余数为4。
所以将时钟向后转动(减法)的结果可以用向前转动(加法)来代替!
现在的重点是如何用正数代替负数。从上面的例子中,我们可以感受到一些端倪,发现一些规律。但数学是严谨的。我们不能依靠感觉。
首先介绍一下数学中的一个相关概念:同余
同余的概念
如果两个整数a 和b 除以整数m 所得的余数相等,则称这两个整数a 和b 模m 全等。
写为a==b (mod m)
读作a 和b 模m 全等。
示例:
4 模12=4
16 模12=4
28 模12=4
所以4、16、28 模12 全等。
负数取模
对正数进行取模运算非常简单。但是负数呢?
以下是mod运算:的数学定义
上面是截图。我找不到如何输入“删除边界”符号(粘贴到word中后代码是乱码)。下面是用'L'和'J'来代替上图:中的'removebounds'符号
x 模y=x - y L x/y J
上式的意思是:
x mod y 是x 减去y 乘以x 和y 的商的下限。
以-3 mod 2为例:
-3 模2
=-3 - 2xL -3/2J
=-3 - 2xL-1.5J
=-3 - 2x(-2)
=-3 + 4=1
所以:
(-2) 模12=12-2=10
(-4) 模12=12-4=8
(-5) 模12=12 - 5=7
开始证明
返回时钟问题:
向后2 小时=向前10 小时
向后拨4 小时=向前拨8 小时
向后拨5 小时=向前拨7 小时
注意,这里发现的模式!
结合上面学到的同余的概念。事实上,
(-2) 模12=10
10 模12=10
-2 和10 一致。
(-4) 模12=8
8 模12=8
-4 和8 一致。
我们离成功越来越近了。要将负数替换为正数,我们只需应用同余数的两个定理:
反身性:
a=a (mod m)
这个定理是非常明显的。
线性运算定理:
如果a=b (mod m), c=d (mod m) 则:
(1)a c==b d (mod m)
(2)a * c==b * d (mod m)
如果想看这个定理的证明请看:http://baike.baidu.com/view/79282.htm
所以:
7=7 (模12)
(-2)==10 (模12)
7 -2==7 + 10 (模12)
现在我们求负数的正同余。但不是7-2=7+10,而是7 -2 7 + 10 (mod 12),即计算结果的余数相等。
接下来我们回到二进制问题,看看: 2-1=1的问题。
2-1=2+(-1)=[0000 0010] 原值+ [1000 0001] 原值=[0000 0010] 逆值+ [1111 1110] 逆值
让我们先进行这一步。 -1的补码表示为1111 1110。如果将[1111 1110]视为原码,则[1111 1110]原来=-126。这里去掉了符号位,认为是126。
发现以下规则:
(-1) 模127=126
126 模127=126
那是:
(-1)==126 (模127)
2-1=2+126 (模127)
2-1和2+126的余数结果是一样的!而这个余数就是我们期望的计算结果: 2-1=1
所以一个数的补码实际上是这个数与膜的同余。而这个膜并不是我们的二元系统,而是能够表示的最大值!这就好比一个钟表,旋转一圈后总能在可表示的范围内找到正确的值!
而2+126显然相当于时钟转了一圈,而且由于符号位参与计算,正好与溢出的最高位形成正确的运算结果。
既然补码可以把减法变成加法,那么现在计算机使用的补码呢?为什么补码加1还能得到正确的结果呢?
2-1=2+(-1)=[0000 0010] 原+ [1000 0001] 原=[0000 0010] 补数+ [1111 1111] 补数
若将[1111 1111]视为原码,去掉符号位,则为:
[0111 1111]原始=127
事实上,基于反码的+1只相当于将膜的值增加:
(-1) 模128=127
127 模128=127
2-1=2+127 (模128)
此时表盘相当于每128个刻度转一圈。因此,用补码表示的运算结果的最小值和最大值应为[-128, 128]。
但由于0的特殊情况,没有办法表示128,所以补码的取值范围是[-128, 127]
我的数学一直不太好,所以如果文章中有错误的地方,请指出并给我一些建议!
本文采摘于网络,不代表本站立场,转载联系作者并注明出处:https://www.iotsj.com//kuaixun/4118.html
用户评论
这篇文章让我对计算机的原码、反码、补码有了更深的理解,以前一直搞不明白,现在终于豁然开朗了!
有8位网友表示赞同!
计算机的世界真奇妙,原来还有原码、反码、补码这些东西!
有12位网友表示赞同!
感觉原码、反码、补码有点难理解,不过文章讲得很清楚,让我慢慢消化一下。
有9位网友表示赞同!
学计算机一定要弄明白原码、反码、补码,这可是基础中的基础啊!
有15位网友表示赞同!
以前一直以为计算机直接用二进制表示数据,没想到还有这么多玄机!
有17位网友表示赞同!
原码、反码、补码,这三个概念真的很重要,对理解计算机的运算原理很有帮助。
有15位网友表示赞同!
这篇文章真是及时雨,我最近正好在学习计算机基础知识,原码、反码、补码一直困扰着我。
有20位网友表示赞同!
看完文章,感觉对原码、反码、补码有了更深刻的理解,原来计算机是用这种方式处理数据的!
有14位网友表示赞同!
原码、反码、补码,这三个概念虽然比较抽象,但理解了之后就能更好地理解计算机的运行机制。
有6位网友表示赞同!
文章解释得非常清晰,让我对原码、反码、补码有了更直观的认识。
有10位网友表示赞同!
这篇文章让我对原码、反码、补码有了更深入的了解,原来计算机内部的运算并不是简单的加减法。
有8位网友表示赞同!
原码、反码、补码,这三个概念是理解计算机运算的关键,一定要认真学习!
有5位网友表示赞同!
感觉原码、反码、补码有点绕,需要多花点时间琢磨一下。
有11位网友表示赞同!
计算机真是太神奇了,用原码、反码、补码来处理负数,真是太巧妙了!
有10位网友表示赞同!
看完文章,感觉自己对计算机的理解又进了一步,感谢作者的分享!
有11位网友表示赞同!
原码、反码、补码,这三个概念很重要,一定要牢牢记住!
有19位网友表示赞同!
原码、反码、补码,这三个概念其实并不难,只要理解了原理就很容易了。
有12位网友表示赞同!
感觉原码、反码、补码有点像数学里的概念,需要多做练习才能熟练掌握。
有14位网友表示赞同!
文章写得很好,通俗易懂,让我对原码、反码、补码有了更清晰的认识。
有6位网友表示赞同!
原码、反码、补码,这三个概念是学习计算机基础知识的重要内容,一定要认真学习!
有10位网友表示赞同!