定义
逻辑左移(LLS,Logical Left Shift):低位补零。
逻辑右移(LRS,Logical Right Shift):高位补零。
算术左移(ALS,Arithmetic Left Shift):符号位不变,低位补零。
算术右移(ARS,Arithmetic Right Shift):高位补符号位。
注意:以上4种定义,所有位(包括符号位)要同步移动。
结论
1. 逻辑左移与算术左移完全相同。
2. 正数:逻辑右移与算术右移完全相同。
3. 负数:逻辑右移与算术右移不同。
以上结论从严格从定义上得到。接下来解释一下多数人的疑惑。
疑惑
1. 负数的逻辑左移,明显符号位被移走了,1变成0了呀,负数不就变成正数了吗?为何能和算术左移一样呢?
首先呢,从定义上看,逻辑左移和算术左移就是一样的,这个问题准确来讲是问为什么这么定义?
其实这是一个常见的误区。我们要注意,计算机是按补码
存储的。
假设计算机的位长是4
位,1111b
(b
表示二进制)这个数是几?这个数的实际大小应该是保持符号位不变,其他位取反再加1
,那么这个数是-1
。
计算机位长4 bit
能表示的数值范围为-8 ~ 7
,即1000b ~ 0111b
,我们只看负数部分:
原值 | 左移1位 | |||
十进制 | 二级制 | 二级制 | 十进制 | 说明 |
-1 | 1111 | 1110 | -2 | 扩大2倍 |
-2 | 1110 | 1100 | -4 | 扩大2倍 |
-3 | 1101 | 1010 | -6 | 扩大2倍 |
-4 | 1100 | 1000 | -8 | 扩大2倍 |
-5 | 1011 | 0110 | 6 | 溢出,undifined |
-6 | 1010 | 0100 | 4 | 溢出,undifined |
-7 | 1001 | 0010 | 2 | 溢出,undifined |
-8 | 1000 | 0000 | 0 | 溢出,undifined |
我们看到,从-5
开始,左移1位,全部会溢出。从数值上来看,-5
左移1位,应该扩大2倍至-10
,但是-10
显然超出了4 bit
字长计算机的表示范围,也就是溢出
,溢出
的结果当然是不确定的,不可信。即使你保持符号位不变,4 bit
也无法表示出-10
。
思考一下,使得我们疑惑的,无非是:次高位如果为0(也就是上表的-5 ~ -8 这些数)左移1位之后会出现符号反转
,,非常奇妙的是,这些数左移1位之后恰好全部溢出
!
这是巧合吗?
假设计算机位长n bit
,那么可表示的负数范围为 -2n-1~ -1 。
如图,将[-2n-1, -1]分成连续的两段:
└─────────────┘ └───────────┘
-2n-1 -(2n-2+1) -2n-2 -1
10 00...0b
10 11...1b
11 00...0b
11 11...1b
- 第一段 [-2n-1, -(2n-2+1)] 对应次高位为0的情况:
此时左移1位(即乘以2),符号位反转,但是数值上恰好都溢出了。 - 第二段 [-2n-2, -1] 对应次高位为1的情况:
此时左移1位(即乘以2),符号位不变,数值上也不会溢出。
结论:次高位为1时,逻辑左移不会改变符号;次高位为0时,逻辑左移数值上一定会溢出,此时已经没有意义。综上,逻辑左移与算术左移相同。