Java的原码、补码、反码以及<<、>>、>>>等位移运算介绍与使用
一、Java的原码、补码、反码
具体概念在各大网站博文上多如牛毛,此处不赘述,直接上重点:
首先,我们通常所说的原码、补码、反码都属于机器数,而机器数的最左边一位为符号位,用来标识正数还是负数;0为正数,1为负数。为了解决机器内负数的符号位参加运算的问题,总是将减法运算变成加法运算,也就引进了反码和补码这两种机器数。
简单来说:
原码是给人类看的,比如十进制数字3可以表示为二进制11——实际上是32位,只是11之前的0省略了而已,比如你可以打印—Integer.toBinaryString(3),得到的是11——实际上这个11是补码,而不是原码。
而补码则是给计算机看的,比如上面例子讲到的。如果我们打印Integer.toBinaryString(-3),得到的则是:11111111111111111111111111111101,这一串二进制就是-3的二进制补码表示,如果是我们人类能看懂的-3的二进制表示法则为:10000000000000000000000000000011,这一串二进制数字是原码,这也印证了上面说的32位。
原码、反码、补码之间进行转换的是反码,具体计算规则下面介绍。
(一)正数
正数的原码、补码、反码都一样,记住就好,不用纠结其他;而我们通常所说的三者之间的计算指的是负数。
(二)负数
负数的三者之间计算公式为:
原码 —>反码:符号位不变,数值位取反。
反码 —>补码:符号位不变,数值位加1。
反过来转换道理同上。
以-3为例:
原码:10000000000000000000000000000011(给人类看的)
反码:11111111111111111111111111111100(转换途径)
补码:11111111111111111111111111111101(给机器看的)
如何验证对错呢?可以打印Integer.toBinaryString(-3),得到的就是-3的补码。
二、位移运算
位移运算只有三种,<<、>>、>>>,分别称作,左移、右移(带符号右移)、无符号右移。
一、左移
左移多少位则将高位(左边的)移出,低位(右边的)补0。
比如,3 << 2
0000 0000 0000 0000 0000 0000 0000 0011左移2位,最左边的两个0移出,右边补两个0,为0000 0000 0000 0000 0000 0000 0000 1100。
即11(二进制补码表示)变为1100,即为12(十进制)。
3 << 29为0110 0000 0000 0000 0000 0000 0000 0000,即1610612736。
3 << 30为1100 0000 0000 0000 0000 0000 0000 0000,即-1073741824,符号位为1,表示为负数,然后是2的30次方为1073741824。
再比如,-3 << 2
1000 0000 0000 0000 0000 0000 0000 0011(原码)
1111 1111 1111 1111 1111 1111 1111 1100(反码:原码取反,符号位不变)
1111 1111 1111 1111 1111 1111 1111 1101(补码:反码 + 1)
左移后变为:
1111 1111 1111 1111 1111 1111 1111 0100(补码)
1111 1111 1111 1111 1111 1111 1111 0011(反码:补码 -1)
1000 0000 0000 0000 0000 0000 0000 1100(原码:反码取反,符号位不变)
即为-12。
通俗理解:
在左移的位数没有溢出的前提下,不管正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方。
特殊情况
在左移的时候位数溢出的情况下,上面的原理不可行。
比如,3 << 31,溢出一位,舍弃,2^31为2147483648,最高位为1,-2147483648。
如果3<<32,则和原来一致,等于未曾移动。33位等同于1位,34位等同于2位。
总结:左移运算,在一般情况下,不管正负都相当于乘以2的n次方;但是当位移运算较大,或者虽然位移位数很小但数字本身较大导致位数溢出,则以上原理不适用——此时需要通过补码进行位移运算;在32位二进制表示下,移动32位等于未移动,33位移动一位,以此类推。
二、右移和无符号右移
1.右移
通常我们说的右移,指的是>>,被称作有符号右移。和左移道理一样,只需要移位就行,左边不足部分补0即可。比如,9 >> 3,得到1,9>>4 = 0
简单说来就是除以2^n即可。
注意:
1.在右移32位时,等于没有位移,超过的,道理通左移,可以自行测试;
2.右移之时,若该数字的最左边溢出,则最终为0,比如,9>>4,9>>5,因为9的最高位为从右数第四位,即1001,所以右移4位为0,之后右移更多位依然为0,直到达到32位。及至溢出32位,则情况不一致。一般在32位以内的移位足够,超过的运用不多;不过可以明确的是不全部为0。比如,9>>32 = 0;9 >> 33 = 4; 9 >> 34 = 2; 9 >> 35 = 1; 9 >> 36 = 0;之后又是0.
以上说的都是正数,那么负数会如何呢?
道理同上,右移之后左边不足之处补1,因为>>是有符号位移,符号位是0,则补0,是1,则补1.如-9 >> 3 = -2.
2.无符号右移
正数和右移一样,负数会如何呢?
负数右移,左边全部补0。
总结:无符号右移(>>>),无论正负数,左侧不足位数全部补0;
简介计算——只针对正数,右移几位即为除以该数的2^n.
两者的区别和联系
正数,两者并无区别;
负数,>>左边不足位数补1,>>>不足位数补0.
三、结论
总结如下:
一)原码、反码、补码三者都属于机器数,一般来说,目前机器——也就是计算机,直接参与运算的是补码,也即,补码是给机器看的;而原码是给人看的;反码是其中转换的媒介。计算公式如下:
1.若为正数,三者相同;
2.若为负数,转换如下:
原码 ——> 反码:符号位不变,数值位取反;
反码 ——> 补码:符号位不变,反码 + 1。
反之则反是。
二)参与计算的都是补码;
三)一般的,在没有数字位溢出的情况下,左移相当于乘以2的n次方,右移相当于除以2的n次方;正数的右移和无符号右移一致,负数的右移左边补1,负数的无符号右移左边补0。所以一个很小的负数右移很小几位,会得到一个很大的数字。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/2757.html