二进制溢出后怎么得到正确数值(编程基础必备知识:二进制位运算符)
今天看到一些关于右移和无符号右移的博客解释,发现好多都要么没有实践随意说,有的甚至乱说,说无符号右移补啥的都有.就自己整理了一下.看本文之前,你需要对二进制、十进制及其运算有一定的概念基础.,我来为大家科普一下关于二进制溢出后怎么得到正确数值?以下内容希望对你有帮助!
二进制溢出后怎么得到正确数值
今天看到一些关于右移和无符号右移的博客解释,发现好多都要么没有实践随意说,有的甚至乱说,说无符号右移补啥的都有.就自己整理了一下.看本文之前,你需要对二进制、十进制及其运算有一定的概念基础.
& 按位与
同为1得1,否则为0;
| 按位或
有1得1,其他为0;
^ 按位异或
相异得1,否则得0;
如1-0得1,0-1得1.
~ 取反
1变0,0变1;
<< 左移
x<<n;x * 2^n左移(符号位不动,正负数皆右补0)
>> 右移
x>>n;x /2^n丢弃右边指定位数,左边补上符号位(0正,1负,符号位位于最左位置)
>>> 无符号右移
正数时候和右移是一样的.丢弃右边指定位数,左边全是补上0
负数举例:
System.out.println(-2>>1);
System.out.println(-2>>>1);
# 结果:
-1
2147483647
为了说清无符号右移,需要知道原码、反码和补码;
原码、反码和补码
原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。
反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。
补码:反码加1称为补码。
负数以其正值的补码形式表达.
验证一下:
System.out.println(Integer.toBinaryString(2));
// 对2取反,得到:
System.out.println(Integer.toBinaryString(~2));
// 取-2,可以看到,就是2取反后 1的结果
System.out.println(Integer.toBinaryString(-2));
// 再看一下5和-5的
System.out.println(Integer.toBinaryString(5));
System.out.println(Integer.toBinaryString(~5));
System.out.println(Integer.toBinaryString(-5));
# 2 -2的结果
10
11111111111111111111111111111101
11111111111111111111111111111110
# 5 -5的结果
101
11111111111111111111111111111010
11111111111111111111111111111011
再看右移和无符号右移
先再解释一下符号位:我们知道int占用4字节大小,数值范围-2147483648~2147483647,转成二进制,就是10000000000000000000000000000000 ~ 01111111111111111111111111111111,可以清晰看到,第一位符号位,是决定的这个数的正负.
前面知道了-2的二进制表示是11111111 11111111 11111111 11111110,那么右移1位,那就是把最右边的0挤掉了,得到1111111 11111111 11111111 11111111,这样少了一位,右移的概念说补符号位,-2是负数,那就是在最左补一个1,得到11111111 11111111 11111111 11111111(如果还有空位的话要补0,这里只移了一位,没空位了).
简单验证一下,1的二进制是00000000000000000000000000000001,取反:11111111111111111111111111111110,再取补码,显然就是我们刚做-2>>1得到的结果,也就是-1.(计算器,编程语言,好像都没有一个直接把负的二进制数转十进制或直接运算的!).(实际上,做个逆运算,把得到的11111111 11111111 11111111 11111111减去1,再取反,就得到其正数时的值1,也可以知道,我们算出来的结果是-1.)
上面只是验证了右移..再看无符号位移,为什么-2>>>1的结果是2147483647,先看一下这个结果的二进制数01111111111111111111111111111111(最大的一个int).这个通过概念比较好理解,前面右移的那里,我们知道-2的二进制表示,也知道右移一位后的结果,区别是,前面不是补符号位,而是补0,补0,那就是01111111111111111111111111111111,也就是2147483647.
所以你理解一下,无符号右移的无符号,指的就是正负符号,全名可以理解为:无视正负符号的右移,左边全部补0,所以你是不是也可以回答:为什么无符号右移,得到必是非负数这类问题了?
应用
左移和右移,可以在做一些做2的倍次运算时使用,提高你的运算效率.无符号右移的应用,我们比较熟悉hashCode()中就用到了.
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
拓展
思考一下,为什么没有无符号左移?
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com