不同的进制,每一位的位权不一样。如数字 K n K n − 1 . . . K 2 K 1 K 0 . K − 1 K − 2 . . . K − m K_{n}K_{n-1}...K_{2}K_{1}K_{0}.K_{-1}K_{-2}...K_{-m} KnKn−1...K2K1K0.K−1K−2...K−m,以小数点为分界线,小数点以前的n+1位数字的位权从右到左依次是 r 0 , r 1 , . . . , r n − 1 r^{0},r^{1},...,r^{n-1} r0,r1,...,rn−1;小数点以后的m位数字的位权从左至右依次是 r − 1 , r − 2 , . . . , r − m r^{-1},r^{-2},...,r^{-m} r−1,r−2,...,r−m.其中r是该数字的基数:不同进制的基数不同,十进制每一位可能出现的字符是0~9共10个,则十进制的基数是10;二进制每一位可能出现的字符是0或1,则二进制的基数是2.
任意进制要想转换为十进制,只需要将该数字的每一位与本位的位权相乘,再将结果相加即可。
二进制转为十进制: 101.1 = 1 × 2 2 + 0 × 2 1 + 1 × 2 0 + 1 × 2 − 1 = 5.5 101.1 = 1\times2^{2}+0\times2^{1}+1\times2^{0}+1\times2^{-1}=5.5 101.1=1×22+0×21+1×20+1×2−1=5.5
八进制转为十进制: 5.4 = 5 × 8 0 + 4 × 8 − 1 = 5.5 5.4 = 5\times8^{0}+4\times8^{-1}=5.5 5.4=5×80+4×8−1=5.5
十六进制转为十进制: 5.8 = 5 × 1 6 0 + 8 × 1 6 − 1 = 5.5 5.8=5\times16^{0}+8\times16^{-1}=5.5 5.8=5×160+8×16−1=5.5
十进制转换为其他进制要分为小数点前后的整数部分和小数部分。对于整数部分使用除基取余的方法,先取得“余”是整数的低位;对于小数部分使用乘基取整的方法,先取的“整”是小数的高位。
对于任意的r进制数字要转换为十进制: K n K n − 1 . . . K 2 K 1 K 0 . K − 1 K − 2 . . . K − m = K n × r n + K n − 1 × r n − 1 + . . . + K 2 × r 2 + K 1 × r 1 + K 0 × r 0 + K − 1 × r − 1 + K − 2 × r − 2 + . . . + K − m × r − m K_{n}K_{n-1}...K_{2}K_{1}K_{0}.K_{-1}K_{-2}...K_{-m}=K_{n}\times r^{n}+K_{n-1}\times r^{n-1}+...+K_{2}\times r^{2}+K_{1}\times r^{1}+K_{0}\times r^{0}+K_{-1}\times r^{-1}+K_{-2}\times r^{-2}+...+K_{-m}\times r^{-m} KnKn−1...K2K1K0.K−1K−2...K−m=Kn×rn+Kn−1×rn−1+...+K2×r2+K1×r1+K0×r0+K−1×r−1+K−2×r−2+...+K−m×r−m.
其整数部分若除以基数即 K n × r n + K n − 1 × r n − 1 + . . . + K 2 × r 2 + K 1 × r 1 + K 0 × r 0 r = K n × r n − 1 + K n − 1 × r n − 2 + . . . + K 2 × r 1 + K 1 × r 0 . . . . . . K 0 \frac{K_{n}\times r^{n}+K_{n-1}\times r^{n-1}+...+K_{2}\times r^{2}+K_{1}\times r^{1}+K_{0}\times r^{0}}{r}=K_{n}\times r^{n-1}+K_{n-1}\times r^{n-2}+...+K_{2}\times r^{1}+K_{1}\times r^{0}......K_{0} rKn×rn+Kn−1×rn−1+...+K2×r2+K1×r1+K0×r0=Kn×rn−1+Kn−1×rn−2+...+K2×r1+K1×r0......K0,其中 K 0 K_{0} K0为余数,其余的为商,并且 K 0 < r K_{0}
其小数部分若乘以基数即 K − 1 × r − 1 + K − 2 × r − 2 + . . . + K − m × r − m × r = K − 1 × r 0 + K − 2 × r − 1 + . . . + K − m × r − m + 1 K_{-1}\times r^{-1}+K_{-2}\times r^{-2}+...+K_{-m}\times r^{-m} \times r=K_{-1}\times r^{0}+K_{-2}\times r^{-1}+...+K_{-m}\times r^{-m+1} K−1×r−1+K−2×r−2+...+K−m×r−m×r=K−1×r0+K−2×r−1+...+K−m×r−m+1,由于r是大于1的,则r的负指数必然小于1,因此该结果的整数部分为 K − 1 K_{-1} K−1,这样就得到了小数部分的第一位,以此类推可以得到更低的几位。
这里需要注意的是,十进制转换为其他进制的时候,想要得到目标进制整数部分的时候需要除法操作取余数,每次的被除数是上一次的商,这样算下去一定会算到商为0,此时整数部分的计算也就完成了。而小数部分需要进行乘法操作,每次都要用小数部分与基数相乘取积的整数部分,直到积为0为止,但是有时候我们永远都无法乘到0如0.3转换为二进制,几次乘法之后会发现开始了循环导致永远也乘不到严格的0,这也就导致了小数部分不精确,因此十进制可能无法严格转换为其他进制。
十进制转换为二进制:75.3
整数部分: 75 2 = 37...1 \frac{75}{2}=37...1 275=37...1
37 2 = 18...1 \frac{37}{2}=18...1 237=18...1
18 2 = 09...0 \frac{18}{2}=09...0 218=09...0
09 2 = 04...1 \frac{09}{2}=04...1 209=04...1
04 2 = 02...0 \frac{04}{2}=02...0 204=02...0
02 2 = 01...0 \frac{02}{2}=01...0 202=01...0
01 2 = 00...1 \frac{01}{2}=00...1 201=00...1
整数部分结果为1001011
小数部分: 0.3 × 2 = 0.6 = 0 + 0.6 0.3\times2=0.6=0+0.6 0.3×2=0.6=0+0.6
0.6 × 2 = 1.2 = 1 + 0.2 0.6\times2=1.2=1+0.2 0.6×2=1.2=1+0.2
0.2 × 2 = 0.4 = 0 + 0.4 0.2\times2=0.4=0+0.4 0.2×2=0.4=0+0.4
0.4 × 2 = 0.8 = 0 + 0.8 0.4\times2=0.8=0+0.8 0.4×2=0.8=0+0.8
0.8 × 2 = 1.6 = 1 + 0.6 0.8\times2=1.6=1+0.6 0.8×2=1.6=1+0.6
. . . . . . ...... ......
小数部分结果为011001…
则75.3转换为二进制为1001011.01001…
二进制与八进制和十六进制可以快速转换。三位二进制可以组成一位八进制;四位二进制可以组成一位十六进制。若二进制位数不够,小数点前需高位补0;小数点后需低位补0.
二进制 —> 八进制:1111000010.011010 —> 001 111 000 010 . 011 010 —> 1702.32
二进制 —> 十六进制:1111000010.01101000 —> 0011 1100 0010 . 0110 1000 —> 3C2.68
八进制 —> 二进制:251.5O —> 010 101 001 . 101
十六进制 —> 二进制:AE86.1H —> 1010 1110 1000 0110 . 0001
真值就是我们平常习惯使用的十进制数字,机器数就是这些我们惯用的十进制数字在计算机中存储的二进制形式,正负号在机器数中是需要被数字化的,0代表整数,1代表负数。
真值 机器数
+15 0 1111
-08 1 1000
BCD(Binary-Coded Decimal)码就是用二进制编码的十进制,他分为3种,分别是8421码、余3码和2421码。其中8421码和2421码为有权码,余3码为无权码。这三种编码方式都是用4位二进制数字表示1位十进制,只不过映射方式不同。
8421码与十进制的映射关系如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 |
0101+1000=1101,显然1101这个编码无法对应任何一个十进制数字。这个时候需要把非法结果+0110修正为合法结果。上述结果1101+0110=1 0011,再将高位补全得到0001 0011,这样就可以和表中一一对应。
此处的修正方法为计算机需要使用的方法,我们平常计算的时候可以直接用十进制算出结果,然后将每一个十进制位对应到8421编码即可。之所以+110即6是因为8421码从1010开始就无法对应十进制位,此时真值为10,再加上6便可以向前进位而保留低位。
余3码就是在8421码的基础上,每一个编码+0011,其与十进制映射关系如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 |
2421码每一位的权值由高到低依次是2、4、2、1,其与十进制映射关系如下:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
0000 | 0001 | 0010 | 0011 | 0100 | 1011 | 1100 | 1101 | 1110 | 1111 |
在2421码中,规定0~4的编码以0开头,5~9的编码以1开头。若不遵守这个规定,则此编码会有歧义。如十进制的5,按照2421的权值来看,可以有0101和1011两种编码方式,这显然是不应该出现的。
无符号整数的表示有如下特征:
无符号整数的加法运算只需要从最低位开始,按位相加,向高处进位。而无符号整数的减法运算
需要先将减法转换为加法,然后按照加法规则相加即可。这样做一方面是因为加法运算的电路简单且成本低,另一方面可以让计算机用同样的方法处理运算,计算机擅长做重复的事情。
如A-B需要将其转化为等价的加法形式A+(-B),此处的-B不是前者B的相反数,而是通过将减数B全部位按位取反,末位+1这个规则得到的。
A:99 —> 01100011
B:09 —> 00001001
计算A-B,先将“B”转换为“-B”:00001001 (按位取反)—> 11110110 (末位+1)—> 11110111
0 1 1 0 0 0 1 1
+1 1 1 1 0 1 1 1
————————
1 0 1 0 1 1 0 1 0 = 90
舍去高位的1bit,得到结果01011010即90
有符号数可以用原码、反码、补码和移码表示,其中移码只能表示整数。原码就是通过真值直接转换为二进制所得到的,只不过最高位是符号位,且符号位不能参与运算。用原码进行计算不方便,而补码可以很方便地进行运算,所以实际运算用的都是补码。
正数的原反补码是一样的。
负数的反码需要将其原码的数值位按位取反,符号位保持不变,负数的补码需要在其反码的末位+1,这个过程同样适用于补码转原码。虽然负数的原反补码是通过变化得来的,但是它们的最高位即符号位不会发生变化,都能够正确的表示正负。
对于负数来说,有一种快捷的从原码转变为补码的方式:从右往左找到第一个“1”,将这个“1”左边的所有数值位按位取反,符号位不变,就可以直接得到该原码的补码。同样也可以由此方法将补码转换为原码。
n+1 bit | 合法表示范围 | 最大的数 | 最小的数 | 真值0的表示 |
---|---|---|---|---|
带符号整数:原码 | − ( 2 n − 1 ) ⩽ x ⩽ 2 n − 1 -(2^{n}-1)\leqslant x\leqslant 2^{n}-1 −(2n−1)⩽x⩽2n−1 | 0 , 111...111 = 2 n − 1 0,111...111= 2^{n}-1 0,111...111=2n−1 | 1 , 111...111 = − ( 2 n − 1 ) 1,111...111= -(2^{n}-1) 1,111...111=−(2n−1) | [ + 0 ] 原 = 0 , 000...000 [+0]_{原}=0,000...000 [+0]原=0,000...000 [ − 0 ] 原 = 1 , 000...000 [-0]_{原}=1,000...000 [−0]原=1,000...000 |
带符号整数:反码 | − ( 2 n − 1 ) ⩽ x ⩽ 2 n − 1 -(2^{n}-1)\leqslant x\leqslant 2^{n}-1 −(2n−1)⩽x⩽2n−1 | 0 , 111...111 = 2 n − 1 0,111...111= 2^{n}-1 0,111...111=2n−1 | 1 , 111...111 = − ( 2 n − 1 ) 1,111...111= -(2^{n}-1) 1,111...111=−(2n−1) | [ + 0 ] 反 = 0 , 000...000 [+0]_{反}=0,000...000 [+0]反=0,000...000 [ − 0 ] 反 = 1 , 111...111 [-0]_{反}=1,111...111 [−0]反=1,111...111 |
带符号整数:补码 | − 2 n ⩽ x ⩽ 2 n − 1 -2^{n}\leqslant x\leqslant 2^{n}-1 −2n⩽x⩽2n−1 | 0 , 111...111 = 2 n − 1 0,111...111= 2^{n}-1 0,111...111=2n−1 | 1 , 000...000 = − 2 n 1,000...000= -2^{n} 1,000...000=−2n | [ 0 ] 补 = 0 , 000...000 [0]_{补}=0,000...000 [0]补=0,000...000 真值0只有一种补码 |
带符号整数:移码 | − 2 n ⩽ x ⩽ 2 n − 1 -2^{n}\leqslant x\leqslant 2^{n}-1 −2n⩽x⩽2n−1 | 1 , 111...111 = 2 n − 1 1,111...111= 2^{n}-1 1,111...111=2n−1 | 0 , 000...000 = − 2 n 0,000...000= -2^{n} 0,000...000=−2n | [ 0 ] 移 = 1 , 000...000 [0]_{移}=1,000...000 [0]移=1,000...000 真值0只有一种移码 |
无符号整数 | 0 ⩽ x ⩽ 2 n + 1 − 1 0\leqslant x\leqslant 2^{n+1}-1 0⩽x⩽2n+1−1 | 1111...111 = 2 n + 1 − 1 1111...111= 2^{n+1}-1 1111...111=2n+1−1 | 0000...000 = 0 0000...000= 0 0000...000=0 | [ 0 ] 移 = 1 , 000...000 [0]_{移}=1,000...000 [0]移=1,000...000 |
原码和反码的合法表示范围完全相同,真值0都有2种形式;
补码和移码的合法表示范围完全相同,比原码多表示一个负数,真值0只有1种形式。
8bit的机器数,用不同的方式解读的结果如图所示。可以看出移码和无符号数的机器数的绝对值越大,其真值就越大。
不同码之间的转化如图所示:
补码的加法运算按位相加即可,向高位进位,符号位参与运算。
A:+19 —> 0,0010011 (原码)
B: -19 —> 1,0010011 (原码)
计算A+B:
直接使用原码运算:
0 0 0 1 0 0 1 1
+1 0 0 1 0 0 1 1
————————
1 0 1 0 0 1 1 0 = 166
显然这个结果是错误的。
A:+19 —> 0,0010011 (原码) —> 0,0010011(补码)
B: -19 —> 1,0010011 (原码) —> 1,1101101(补码)
使用补码运算:
0 0 0 1 0 0 1 1
+1 1 1 0 1 1 0 1
————————
1 0 0 0 0 0 0 0 0 = 0
最高位溢出,保留低8位,得到了正确的结果0。
和无符号整数的减法一样,补码的减法运算也需要将减法转换为等价的加法,也就是将减数B的补码转换为-B的补码。转换规则和无符号整数B转换为-B的方法一样,将 [ B ] 补 [B]_{补} [B]补全部位按位取反后+1,即可得到 [ − B ] 补 [-B]_{补} [−B]补。
从 [ B ] 补 [B]_{补} [B]补转换到 [ − B ] 补 [-B]_{补} [−B]补也有一种简单的算法:找到 [ B ] 补 [B]_{补} [B]补最右边的“1”,将这个“1”左边的全部位按位取反即可得到 [ − B ] 补 [-B]_{补} [−B]补。(注意与前边负数的原码补码转换方法区别)
A:+19 —> 0,0010011(原码) —> 0,0010011(补码)
B: -19 —> 1,0010011(原码) —> 1,1101101(补码)
计算A-B,首先转换为A+(-B)
[ − B ] 补 = 00010011 [-B]_{补}=00010011 [−B]补=00010011
计算A+(-B):
0 0 0 1 0 0 1 1
+0 0 0 1 0 0 1 1
————————
0 0 1 0 0 1 1 0 = 38
定点整数可以用原码、反码、补码和移码表示,定点小数可以用原反补码表示而不能用移码表示。
定点是指小数点的位置固定不变。在定点整数中,我们默认小数点在最低位的后边;在定点小数中,我们默认小数点在符号位和数值最高位之间。因此若需要位数扩展时,两者的扩展位置是不一样的:定点整数在高位扩展,定点小数在低位扩展。
定点小数三种码之间的转换和定点整数三种码之间的转换是完全一致的,运算方法也与定点整数完全一致:加减法需要先转换为补码,减法要先转换为加法,这个转换也和定点整数是一样的。
n+1 bit | 合法表示范围 | 最大的数 | 最小的数 | 真值0的表示 |
---|---|---|---|---|
定点整数:原码 | − ( 2 n − 1 ) ⩽ x ⩽ 2 n − 1 -(2^{n}-1)\leqslant x\leqslant 2^{n}-1 −(2n−1)⩽x⩽2n−1 | 0 , 111...111 = 2 n − 1 0,111...111= 2^{n}-1 0,111...111=2n−1 | 1 , 111...111 = − ( 2 n − 1 ) 1,111...111= -(2^{n}-1) 1,111...111=−(2n−1) | [ + 0 ] 原 = 0 , 000...000 [+0]_{原}=0,000...000 [+0]原=0,000...000 [ − 0 ] 原 = 1 , 000...000 [-0]_{原}=1,000...000 [−0]原=1,000...000 |
定点整数:反码 | − ( 2 n − 1 ) ⩽ x ⩽ 2 n − 1 -(2^{n}-1)\leqslant x\leqslant 2^{n}-1 −(2n−1)⩽x⩽2n−1 | 0 , 111...111 = 2 n − 1 0,111...111= 2^{n}-1 0,111...111=2n−1 | 1 , 111...111 = − ( 2 n − 1 ) 1,111...111= -(2^{n}-1) 1,111...111=−(2n−1) | [ + 0 ] 反 = 0 , 000...000 [+0]_{反}=0,000...000 [+0]反=0,000...000 [ − 0 ] 反 = 1 , 111...111 [-0]_{反}=1,111...111 [−0]反=1,111...111 |
定点整数:补码 | − 2 n ⩽ x ⩽ 2 n − 1 -2^{n}\leqslant x\leqslant 2^{n}-1 −2n⩽x⩽2n−1 | 0 , 111...111 = 2 n − 1 0,111...111= 2^{n}-1 0,111...111=2n−1 | 1 , 000...000 = − 2 n 1,000...000= -2^{n} 1,000...000=−2n | [ 0 ] 补 = 0 , 000...000 [0]_{补}=0,000...000 [0]补=0,000...000 真值0只有一种补码 |
定点小数:原码 | − ( 1 − 2 − n ) ⩽ x ⩽ 1 − 2 − n -(1-2^{-n})\leqslant x\leqslant 1-2^{-n} −(1−2−n)⩽x⩽1−2−n | 0.111...111 = 1 − 2 − n 0.111...111= 1-2^{-n} 0.111...111=1−2−n | 1.111...111 = − ( 1 − 2 − n ) 1.111...111= -(1-2^{-n}) 1.111...111=−(1−2−n) | [ + 0 ] 原 = 0.000...000 [+0]_{原}=0.000...000 [+0]原=0.000...000 [ − 0 ] 原 = 1.000...000 [-0]_{原}=1.000...000 [−0]原=1.000...000 |
定点小数:反码 | − ( 1 − 2 − n ) ⩽ x ⩽ 1 − 2 − n -(1-2^{-n})\leqslant x\leqslant 1-2^{-n} −(1−2−n)⩽x⩽1−2−n | 0.111...111 = 1 − 2 − n 0.111...111= 1-2^{-n} 0.111...111=1−2−n | 1.111...111 = − ( 1 − 2 − n ) 1.111...111= -(1-2^{-n}) 1.111...111=−(1−2−n) | [ + 0 ] 反 = 0.000...000 [+0]_{反}=0.000...000 [+0]反=0.000...000 [ − 0 ] 反 = 1.111...111 [-0]_{反}=1.111...111 [−0]反=1.111...111 |
定点小数:补码 | − 1 ⩽ x ⩽ 1 − 2 − n -1\leqslant x\leqslant 1-2^{-n} −1⩽x⩽1−2−n | 0.111...111 = 1 − 2 − n 0.111...111= 1-2^{-n} 0.111...111=1−2−n | 1.000...000 = − 1 1.000...000= -1 1.000...000=−1 | [ 0 ] 补 = 0 , 000...000 [0]_{补}=0,000...000 [0]补=0,000...000 真值0只有一种补码 |