数的机器码表示
为了妥善的处理数据运算过程中符号位的问题,于是就产生了
把符号位和数值位一起编码起来
表示相应的数的各种表示方法。例如我们熟悉的原码、反码、补码、移码等。通常将未经
编码的数称为真值,编码后的数称为
机器数或者机器码。
原码
定点整数
若定点整数的原码形式位xnxn−1⋅⋅⋅x1x0,其中xn为符号位,则原码表示的定义为:
x[原]={x2n−x=2n+∣x∣0⩽x<2n−2n<x⩽0
在上式中,x代表的是真值。
例如,x=+7,化为二进制表示为x=+0111;x[原]=0111。
x=−7,化为二进制表示为x=−0111;x[原]=23−(−0111)=1000+0111=1111。
我们可以总结出来:
-
对于正数x=+xn−1...x1x0,它的原码是它自己本身,常常在最高位前面补0,代表它是一个正数。
- x[原]=0xn−1...x1x0
-
对于0,根据原码的定义则有两种表示形式:
- +0=+0n−1...0100
- 此时正0的原码为+0[原]=00n−1...0100
- −0=−0n−1...0100
- 此时负0的原码为−0[原]=10n−1...0100
-
对于负数x=−xn−1...x1x0,它的原码是在最高位前面补1,代表它是一个负数。
- x[原]=−xn−1...x1x0
对于一个定点整数原码xnxn−1...x1x0,最高位xn代表符号位,用0来表示正数,用1来表示负数。而xn−1...x1x0则代表的是数值位。它的大小就是该原码对应真值的绝对值。
我们很容易求出它的范围[−(2n−1),2n−1]
定点小数
假设定点小数的原码形式为xs.x1x2...xn(实际上小数点是不存储的),其中xs代表符号位。则原码的定义为:
x[原]={x1−x=1+∣x∣0⩽x<1−1<x⩽0
在上式中,x代表的是真值。
例如,x=+0.875,化为二进制表示为x=+0.111;x[原]=0.111。
x=−0.875二进制表示为x=−0.111;x[原]=1.000−(−0.111)=1.000+0.111=1.111。 我们可以总结出来:
-
对于正数x=+0.xn−1...x1x0,它的原码是它自己本身,常常在最高位前面补0,代表它是一个正数。(注意,前面的0.实际上是不存储的,也就是实际最高位是xn−1)
- x[原]=0.xn−1...x1x0
-
对于0,根据原码的定义则有两种表示形式:
- +0=+0.0n−1...0100
- 此时正0的原码为+0[原]=0.0n−1...0100
- −0=−0.0n−1...0100
- 此时负0的原码为−0[原]=1.0n−1...0100
-
对于负数x=−0.xn−1...x1x0,它的原码是在最高位前面补1,代表它是一个负数。(注意,前面的0.实际上是不存储的,也就是实际最高位是xn−1)
- x[原]=−1.xn−1...x1x0
对于一个定点小数原码 xs.x1x2...xn,最高位 xs代表符号位,用0来表示正数,用1来表示负数。而x1x2...xn则代表的是数值位。它的大小就是该原码对应真值的绝对值。
我们很容易求出它的范围[2−n−1,1−2−n]
原码的计算
原码虽然表示极为简单,但是最大的问题就是加法运算十分复杂。
两数相加时,我们需要考虑两个数的符号,如果符号相同,我们可以把数值位直接相加,然后在最高位前边添加上原来的符号位。但如果符号位不相同,那么我们就要考虑进行减法运算。进行减法的时候,我们需要考虑数值位的绝对值大小来决定符号位。这也就是原码运算的缺点:参与运算复杂,需要将数值位与符号位分开考虑。
反码
当进行减法的时候,人们想到如何把减法变为加法,那么这样会更加简便,只靠加法器就可以完成运算。比如
1−1=0
0001−0001=0000
1+(−1)=0
0001+1001=1010=−2
显然是计算错误的。
于是人们引入了反码来表示负数。
定点整数
设定点整数的反码形式为xnxn−1⋅⋅⋅x1x0,xn代表符号位。
则
x[反]={x2n−1+x=2n−1−∣x∣0⩽x<2n−1−(2n−1)<x⩽0
对于正数,它的反码为它本身,如+7=0111,它的反码为0111
对于负数,它的反码表示为:符号位不变,数值位取反。,如-7=1000
对于0
定点小数
假设定点小数的反码形式为xs.x1x2...xn(实际上小数点是不存储的),其中xs代表符号位。则反码的定义为:
x[反]={x2−2−n+x=2−2−n−∣x∣0⩽x<1−1<x⩽0
在上式中,x代表的是真值。
反码的运算
注:如果最高位相加后产生进位,则最后得到的结果要加1。
1+(−1)=0
0001+1110=1111=-0
在以-126+127=1为例
10000001+01111111=100000000
- 进了一位,末位加一
- 10000000+01111111+1
- 最后结果为00000001
也就是说,反码解决了把减法化为加法的问题。
补码
补码的由来
为了解决原码的计算问题,人们引入了补码。
我们先从时钟的例子来介绍补码的原理。
比如我们将定在五点的钟表跳到三点,有2种调法:
我们既可以顺时针调也可以逆时针调。也就是说我们5−2和5+10的效果是一样的。
而把这种思想引入到计算机中,不就可以把减法转为加法了吗?
5−2=5+10(MOD12)5+(−2)=5+10(MOD12)−2=10(MOD12)
在上面的式子中,在模为12的情况下,-2的补码就是10。一个负 数用其补码代替,同样可以得到正确的运算结果。
那什么是模呢?
计算机中运算器、寄存器、计数器都有一定的位数,不可能容纳无限大的任意数。当运算结果超出实际的最大表示范围, 就会发生溢出,此时所产生的溢出量就是模(module)
可以把模定义为一个计量器的容量。
如一个八位计数器,0000 0000~1111 1111
,它表示的范围就是[0,255]
。当计数器表示为1111 1111
时,如果计数器再加一,那么此计数器就会溢出。计数器上的数值会变成0000 0000.而此计数器的溢出量就是256.
假设此计数器表示一个定点小数,它表示的范围就是[0,2-2−8]。当表示最大的时候,计数器值为1.111 1111当计数器加一的时候,那么计数器就会清零,变为0.0000000。那么此此定点小数的溢出量就是2.
从上面我们可以推导出,一个n+1
位定点整数xnx(n−1)...x2x1x0,它的溢出量为2n+1,所以模为2n+1。
任意一个定点小数xs.x1x2...xn,它的溢出量是2,所以模为2。
而在计算机中,机器能表示的数据位数是固定的, 其运算都是有模运算。若运算结果超出了计算机所能表示的数值范围, 则只保留它的小于模的低n+1位的数值,超过n+1 位的高位部分就自动舍弃了。
下面我们来引入补码的定义:
定点整数
定点整数的补码形式为xnxn−1⋅⋅⋅x1x0,其中xn为符号位,补码表示的定义为:
x[补]={x2n+1+x=2n+1−∣x∣0⩽x<2n−2n⩽x⩽0
在上式中,x代表的是真值。
例如,x=+7,化为二进制表示为x=+0111;x[补]=0111。
x=−7,化为二进制表示为x=−0111;x[补]=24+(−0111)=10000−0111=1001。
我们可以总结出来:
-
对于正数x=+xn−1...x1x0,它的补码是它自己本身,常常在最高位前面补0,代表它是一个正数。
-
x[补]=0nxn−1...x1x0
-
对于0,根据补码的定义:
-
对于负数x=−xn−1...x1x0
常常可以通过把数值位按位取反,然后末位加一来计算负数的补码。
- 如求−127的补码
- $[-0111 1111]_{[补]}=10000 0000-01111111 $
- 10000000=11111111+1
- [−01111111][补]=11111111−01111111+1,这一步刚刚说明了上面的计算方法的原理。
−128的补码的求法。
- -128=-1000 0000
- [−10000000][补]=11111111−10000000+1=10000000
其实还有一个更为渐变的补码的求法:**从右到左遇到第一个 1 的前面各位取反。**也就是从右向左,遇到1之前,还保持原样。遇到1之后,各位取反。以-126为例:−126=−01111110
[-01111110]的补码位10000010,10是不变的。而黑体部分则是取反的。
对于补码的取值范围,10000000-11111111——- −128~−1
00000000~011111111 ——0~127
推广到n位数,则补码的范围就是[−2n−1,2n−1−1]
定点小数
定点小数的补码形式为xs.x1x2...xn(实际上小数点是不存储的),其中xs代表符号位。则补码的定义为:
x[原]={x2+x=2−∣x∣0⩽x<1−1⩽x⩽0
在上式中,x代表的是真值。
例如,x=+0.875,化为二进制表示为x=+0.111;x[补]=0.111。
x=−0.875二进制表示为x=−0.111;x[补]=10.000−(0.111)=1.001。
我们可以总结出来:
-
对于正数x=+0.xn−1...x1x0,它的补码是它自己本身,常常在最高位前面补0,代表它是一个正数。(注意,前面的0.实际上是不存储的,也就是实际最高位是xn−1)
-
x[原]=0.xn−1...x1x0
-
对于0,根据补码的定义:
-
对于负数
按位取反,末位加一,和定点整数一样。虽然我们看起来有一个小数点,但是实际上小数点是不存储的。
定点小数的补码的范围,0000~0111–> [0,0.875]
1000~1111–> [-1,-0.125]
扩展到n位补码
我们很容易求出它的范围$[-1,1-2^{-(n-1)}] $
补码的运算
假设一个二进制整数补码有n+1位,xnxn−1...x2x1x0,则补码与真值的对应关系可以这么表示:
X真值=−2n×xn+∑0n−12ixn
当该数为正整数的时候,xn位变为0,0xn−1...x2x1x0,
X真值=∑0n−12ixn
当该数为负整数的时候,xn位变为1,1xn−1...x2x1x0,
X真值=−2n+∑0n−12ixn
- 以-127为例,-127=-01111111
- 它的补码为10000001
- 从补码求真值的过程:-10000000+1=-01111111-1+1=-01111111
上面我们说到过,计算机中用原码进行加减运算是十分麻烦的,那么我们来看一下用补码来运算。
126−127=0
-
原码
-
补码
- 01111110+10000001=11111111
- 转换为真值后为-1。正确的
- 原理是这样的
- 126-127=-1
- 126+(-127)=-1
- 126+129mod256=-1
- 这里-127等效于129mod256
由此,我们可以看出,补码实际上是可以直接带符号位运算的运算的。
求相反数的补码:由[X]补求[-X]补
带符号位一起取反,然后末位加一
如求我们已知+127的补码求-127的补码:
移码
移码通常用于表示浮点数的阶码。由于阶码是k位的整数,假设定点整数移码形式为ekek−1...e2e1e0最高位为符号位是。移码的传统定义是:
[e]移=2k+e
上式中,e为真值,2k为固定的偏移值常数。
与[x]补的区别:符号位相反
真值 |
补码 |
移码 |
-8 |
1000 |
0000 |
-7 |
1001 |
0001 |
-6 |
1002 |
0002 |
…… |
… |
… |
0 |
0000 |
1000 |
+1 |
0001 |
1001 |
…… |
… |
… |
+7 |
0111 |
1111 |
移码的表示
移码表示的机器数为数的真值在数轴上向右平移了 固定的偏移值。
如八位移码:
移码的特点
- 在移码中,最高位为0表示负数,最高位为1表示正数,这与原 码、补码、反码的符号位取值正好相反。
- 移码为全0时所对应的真值最小,为全1时所对应的真值最大! 因此,移码的大小直观地反映了真值的大小,这将有助于两个 浮点数进行阶码大小比较。
- 真值0在移码中的表示形式是唯一的,即:[+0]移= [0]移= 100…00
- 移码把真值映射到一个正数域,所以可将移码视为无符号数, 直接按无符号数规则比较大小。
- 同一数值的移码和补码除最高位相反外,其他各位相同。
原码、反码、补码、移码
取值范围的一个比较