数据的表⽰之原码,补码,反码和移码
⽬录
⼀、机器数和真值
在学习原码反码,补码和移码之前需要先了解机器数和真值的概念。
1、机器数
⼀个数在计算机中的⼆进制表⽰形式,叫做这个数的机器数。机器数是带符号的,在计算机中⽤⼀个数的最⾼位存放符号正数为0负数为1。
⽐如,⼗进制中的数+3,计算机字长为8位,转换成⼆进制就是0000 0011。如果是-3,就是1000 0011。
那么,这⾥的0000 0011和1000 0011就是机器数。
2、真值
因为第⼀位是符号位,所以机器数的形式值就不等于真正的数值。例如上⾯的有符号数1000 0011,其最
⾼位1代表负,其真正数值是-3⽽不是形式值131(1000 0011转换成⼗进制等于131)。
所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。例:0000 0001的真值=+000 0001=+1,1000 0001的真值=–000 0001=–1
⼆、原码反码补码和移码的基础概念和计算⽅法
在探求机器为何要使⽤补码之前让我们先了解原码反码,补码和移码的概念。对于⼀个数计算机要使⽤⼀定的编码⽅式进⾏存储。原码反码补码和移码是机器存储⼀个具体数字的编码⽅式。
1.原码
原码就是符号位加上真值的绝对值即⽤第⼀位表⽰符号其余位表⽰值。⽐如如果是8位⼆进制:
[+1]原=0000 0001
[-1]原=1000 0001
第⼀位是符号位。因为第⼀位是符号位所以8位⼆进制数的取值范围就是:
[1111 11110111 1111]==>[-127127]
2.反码
反码的表⽰⽅法是:
1. 正数的反码是其本⾝;
2. 负数的反码是在其原码的基础上符号位不变,其余各个位取反。
[+1]=[00000001]原 =[00000001]反 
[-1]=[10000001]原 =[11111110]反
3.补码
补码的表⽰⽅法是:
1. 正数的补码就是其本⾝;
2. 负数的补码是在其原码的基础上符号位不变其余各位取反最后+1(即在反码的基础上+1)。
[+1]=[00000001]原=[00000001]反=[00000001]补 
[-1]=[10000001]原=[11111110]反=[11111111]补
4.移码
移码是作⽤于上的,移码的表⽰⽅法是:
1. 正数的最⾼符号位⽤1表⽰;
补码的最小负数
2. 负数的最⾼符号位⽤0表⽰;
3. 其余原码位不变。
[+1]=[00000001]原 =[00000001]反=[00000001]补=[10000001]移 [-1]=[10000001]原=[11111110]反=[11111111]补=[00000001]移
三、为何要使⽤原码反码,补码和移码
图1 数据的表⽰
计算机可以有三种编码⽅式表⽰⼀个数。对于正数,因为三种编码⽅式的结果都相同,所以不需要过多解释。
[+1]=[00000001]原 =[00000001]反 =[00000001]补
但是对于负数:
[-1]=[10000001]原 =11111110]反 =[11111111]补
可见原码反码和补码是完全不同的。
为何还会有反码和补码呢?
⾸先因为⼈脑可以知道第⼀位是符号位在计算的时候我们会根据符号位选择对真值区域的加减(真值的概念在本⽂最开头)。
但是对于计算机,加减乘数已经是最基础的运算要设计的尽量简单。 计算机辨别"符号位"显然会让计算机的基础电路设计变得⼗分复杂!于是⼈们想出了将符号位也参与运算的⽅法。
根据运算法则减去⼀个正数等于加上⼀个负数即:1-1=1+(-1)=0所以机器可以只有加法⽽没有减法这样计算机运算的设计就更简单了。
于是⼈们开始探索将符号位参与运算并且只保留加法的⽅法。⾸先来看原码:
计算⼗进制的表达式: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类型可以表⽰范围是:[-231231-1]因为第⼀位表⽰的是符号位,⽽使⽤补码表⽰时⼜可以多保存⼀个最⼩值。
移码是为了解决浮点数计算⽽来的,正数的最⾼符号位⽤0来表⽰,负数的最⾼位⽤1来表⽰就会混乱,颠倒了正常的思想观念,所以移码的最⾼符号位正好与原码、反码和补码的最⾼符号位相反,同时它进⾏相关操作也能得到正确的结果。
1000 0001+0111 1111=1000 0000[移]
最⾼符号位1代表正数,所以结果是0。
四、数值表⽰范围
图2 数值表⽰范围公式
上图可知,原码和反码的取值范围都是-127~127,可是补码是-128~127。为什么补码的取值范围⽐原码、反码的多⼀位呢?
举例:
+0=0000 0000[原]
-0=1000 0000[原]
可以看出不对等。
+0=0000 0000[反]
-0=1111 1111[反]
可以看出不对等。
+0=0000 0000[补]
-0=0000 0000[补]
可以看出相等,所以补码少占⽤了⼀个编码。所以它的取值范围要⽐原码和反码多⼀位。五、原码反码补码再深⼊
计算机巧妙地把符号位参与运算并且将减法变成了加法背后蕴含了怎样的数学原理呢?
将钟表想象成是⼀个1位的12进制数。如果当前时间是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 mod 12 = 4
16 mod 12 = 4
28 mod 12 = 4
所以4,16, 28关于模12同余。
负数取模
正数进⾏mod运算是很简单的,但是负数呢?
下⾯是关于mod运算的数学定义:
图 3 取模运算的数学定义
上⾯是截图"取下界"符号不到如何输⼊(word中粘贴过来后乱码)。下⾯是使⽤“L”和“J”替换上图的“取下界”符号:
x mod y=x-y L x/y J
上⾯公式的意思是:
x mod y等于x减去y乘上x与y的商的下界。
以-3 mod 2 举例:
-3 mod 2
=-3-2xL -3/2 J
=-3-2x L-1.5 J
=-3-2x(-2)
=-3+4=1
所以:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。