定点数的移位运算
再开始学习如何计算如何乘除运算的时候,我们应该先了解一下定点数的移位运算
- 先看一下十进制的移位运算
123.456 → 小数点后移一位 1234.56 123.456\xrightarrow[]{小数点后移一位}1234.56 123.456小数点后移一位1234.56 相当于 × 1 0 1 ×10^1 ×101
123.456 → 小数点后移一位 12345.6 123.456\xrightarrow[]{小数点后移一位}12345.6 123.456小数点后移一位12345.6 相当于 × 1 0 2 ×10^2 ×102
123.456 → 小数点前移一位 12.3456 123.456\xrightarrow[]{小数点前移一位}12.3456 123.456小数点前移一位12.3456 相当于 × 1 0 − 1 ×10^{-1} ×10−1
因为是十进制,所以在左右移位的时候进行
×
1
0
n
×10^n
×10n进行运算,那么同理,二进制也是相同原理,左移一位,如果不产生溢出,相当于乘以
2
2
2;右移一位,若不考虑因移出而舍去的末位尾数,相当于除以
2
2
2
移位分两种,为逻辑移位运算和算数移位
- 逻辑移位
- 逻辑移位操作将操作数视为无符号整数,规则是:左移时,高位移出,低位补零;右移时,低位移出,高位补零
- 对于无符号整数的逻辑左移,若高位的
1
1
1移出,则发生溢出
下面是将无符号数 11110 11110 11110进行移位 ( 8 8 8位)
原来 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 |
---|---|---|---|---|---|---|---|---|
右移 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 |
左移 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 |
- 算术移位
- 因为计算机中有符号的整数都是用补码表示的,因此对于有符号整数的移位操作采用补码算术移位方式,规则是:左移时,高位移出,低位补零,若移出的高位不同于移位后的符号位,则发生溢出;右移时,低位移出,高位补符号位,若低位的 1 1 1移出,则影响精度
- 下面是将 − 30 -30 −30 进行移位
符号位 | 2 6 2^6 26 | 2 5 2^5 25 | 2 4 2^4 24 | 2 3 2^3 23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 | |
---|---|---|---|---|---|---|---|---|
1 1 1 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | |
右移一位 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 |
再右移一位 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 |
看出来第一次右移后转换成十进制为
−
15
-15
−15 为原来数的一半
然而第二次有右移后出现了偏差,转成二进制后为
−
7
-7
−7
原因是整数最低位往后会有一个小数点,不会占用任何位,接着就是小数位但是这是整数的算术移位所以会被舍弃
符号位 | 2 6 2^6 26 | 2 5 2^5 25 | 2 4 2^4 24 | 2 3 2^3 23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 | 2 − 1 2^{-1} 2−1 | ||
---|---|---|---|---|---|---|---|---|---|---|
右移两位后 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 小数点(不占位) | 1 1 1 |
也就是
10000111.1
10000111.1
10000111.1转成十进制为
7.5
7.5
7.5
根据以上规律,当左移溢出的时候会出现严重的误差
符号位 | 2 6 2^6 26 | 2 5 2^5 25 | 2 4 2^4 24 | 2 3 2^3 23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 | 转成十进制 转成十进制 转成十进制 | |
---|---|---|---|---|---|---|---|---|---|
1 1 1 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | − 30 -30 −30 | |
左移一位 | 1 1 1 | 0 0 0 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 | − 60 -60 −60 |
左移二位 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | − 120 -120 −120 |
左移三位 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | − 112 -112 −112 |
- [#]继续看定点小数的移位
其实和整数都差不多
符号位 | 2 − 1 2^{-1} 2−1 | 2 − 2 2^{-2} 2−2 | 2 − 3 2^{-3} 2−3 | 2 − 4 2^{-4} 2−4 | 2 − 5 2^{-5} 2−5 | 2 − 6 2^{-6} 2−6 | 2 − 7 2^{-7} 2−7 |
---|---|---|---|---|---|---|---|
1 1 1 | 0 0 0 | 0 0 0 | 1 1 1 | 0 0 0 | 1 1 1 | 0 0 0 | 0 0 0 |
左移一位
符号位 | 2 − 1 2^{-1} 2−1 | 2 − 2 2^{-2} 2−2 | 2 − 3 2^{-3} 2−3 | 2 − 4 2^{-4} 2−4 | 2 − 5 2^{-5} 2−5 | 2 − 6 2^{-6} 2−6 | 2 − 7 2^{-7} 2−7 |
---|---|---|---|---|---|---|---|
1 1 1 | 0 0 0 | 1 1 1 | 0 0 0 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 |
右移一位
符号位 | 2 − 1 2^{-1} 2−1 | 2 − 2 2^{-2} 2−2 | 2 − 3 2^{-3} 2−3 | 2 − 4 2^{-4} 2−4 | 2 − 5 2^{-5} 2−5 | 2 − 6 2^{-6} 2−6 | 2 − 7 2^{-7} 2−7 |
---|---|---|---|---|---|---|---|
1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 0 0 0 | 1 1 1 | 0 0 0 |
反码与补码的移位
- 正数的反码与补码移位和原码相同,这里主要介绍负数计算方法
先写一下正数 12 12 12
符号位 | 2 6 2^6 26 | 2 5 2^5 25 | 2 4 2^4 24 | 2 3 2^3 23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 | |
---|---|---|---|---|---|---|---|---|
原码 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 |
反码 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 |
补码 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 |
下面是负数 − 12 -12 −12
符号位 | 2 6 2^6 26 | 2 5 2^5 25 | 2 4 2^4 24 | 2 3 2^3 23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 | |
---|---|---|---|---|---|---|---|---|
原码 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 |
反码 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 | 1 1 1 | 1 1 1 |
补码 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 1 1 1 | 0 0 0 | 0 0 0 |
规则是(从右往左找到第一个 1 1 1然后这个左边所有的数值位取反):
- 右移:高位补 1 1 1,低位舍弃
- 左移:低位补 1 1 1,高位舍弃
就是蓝色框起来的遵循负数移位规律,而黑色框起来的遵循正数移位规则
下面就将这个补码左移一位
符号位 | 2 6 2^6 26 | 2 5 2^5 25 | 2 4 2^4 24 | 2 3 2^3 23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 | |
---|---|---|---|---|---|---|---|---|
补码 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 |
右移一位
符号位 | 2 6 2^6 26 | 2 5 2^5 25 | 2 4 2^4 24 | 2 3 2^3 23 | 2 2 2^2 22 | 2 1 2^1 21 | 2 0 2^0 20 | |
---|---|---|---|---|---|---|---|---|
补码 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 1 1 1 | 0 0 0 |
这里我们可以验证一下,当左移一位得到的补码转换成原码是
10011000
10011000
10011000,转成十进制是
−
24
-24
−24
右移一位转成原码是
10000110
10000110
10000110,转成十进制是
−
6
-6
−6,验证正确.