算术移位,逻辑移位的一些思考"/>
关于算术移位,逻辑移位的一些思考
今天研究编码方式时,遇见了大小端问题,准备用IDEA测一下本地系统是大端还是小端模式时,又遇到了移位操作,重新温习了一下,特此记录。
注:以下讨论的内容,皆以补码作为数据表示形式,实际计算机系统中也以补码来存储数据。(为什么要强调以补码为前提呢?戳这里)
首先从理论的角度来说,
关于算术移位和逻辑移位
通俗的理解如下:
- 逻辑移位:仅做最纯粹的移位操作,不考虑其他情况
- 算术移位:移位时需要做算术方面的考虑,即考虑到符号位
逻辑移位时,补位都是补0,;算术移位时,对于需要补位的高位(右移),补符号位,需要补位的低位(左移),仍然补0。所以,只有算术右移,是比较特殊的,需要补符号位,其余的移位操作,都是补0
算术移位与逻辑移位比较
- 逻辑左移:高位丢弃,低位补0,在不发生溢出的情况下,效果相当于乘2
- 算术左移:等同于逻辑左移
- 逻辑右移:低位丢弃,高位补0
- 算术右移:低位丢弃,高位补符号位,效果相当于除以2,但可能发生精度丢失
在Java中,移位运算符共有3个:<<
,>>
,>>>
可将前2个视为算术移位运算符,第3个为逻辑右移
<<
左移,a << 1
可实现乘2的效果(前提是不发生溢出)>>
右移,a >> 2
可实现除以2的效果(可能发生精度丢失)>>>
逻辑右移,高位补0,一般不使用
关于<<
运算符的溢出判断标准:
先上结论:若数x的二进制表示的前n+1位全部相同(全为1或全为0),则此时对x左移最多n位,是不会发生溢出的;否则,将发生溢出。
这里可以自己去分2种情况做检验,前n位全为1和全为0,随便举几个数字,做一下左移操作,在将补码转换为原码,再计算出对应的十进制数字,与原数字做比较即可,不赘述。
附:
关于为什么强调以补码为前提
其实在文首讨论对算术移位的通俗理解时,我说算术移位就是要将符号位考虑进来,那么如果数据是用原码来表示(其实原码也是最直观,最符合人的思维的数据表示形式),那么严格来讲,我认为在做算术移位时,符号位应该是不动的,所以算术左移等同于逻辑左移,其实严格来说并不是,只是在补码形式下,两者在实际运用中效果是等同的。比如,二进制数10110(原码表示),其十进制为-6,那么对其做算术移位,若算术左移1位,那么符号位不动,仅对后面的4位做移位,得11100,转换为十进制为-12;那么如果算术右移1位,符号位不动,得10011,转换为十进制为-3(以原码形式存储数据的话,算术移位其实补位都应当补0,符号位不动即可)。然而在JAVA中,移位操作是不会让符号位固定的(符号位也参与移位),而我们知道,为了方便负数的运算,计算机里的数都是以补码来存储的,-6用补码表示则为11010,此时你再去尝试做一下算术左移和右移,就明白为什么本文前面说算术左移的溢出判断标准是那样,以及算术右移为什么不是补0而是补符号位了。
以上
更多推荐
关于算术移位,逻辑移位的一些思考
发布评论