【Java】移位运算
以前一直没有研究二进制的移位运算的应用场景是什么,怎么运算?怎么实现数据的四则运算的? 直到最近,在看Think in
Java的书籍,才真正理解这个东西。下面记录一下学习笔记。
1,二进制
1.1 二进制的表示
我们知道,计算机中所有数据都是以二进制形式存储。例如1(int)在二进制中的表现形式就是
00000000 00000000 00000000 00000001。
而0的二进制就是所有位上均为0。
具体的根据不同的编程语言,可能对于基础数据类型有不一样的字节数的定义。
对于Java而言,Java的八大数据类型的字节数定义如下:
byte:8bits
int:32bits
char:16bits
short:16bits
long:64bits
boolean:-
float:32bits
double:64bits
以下是Think in Java中截取的基础数据类型的定义
1.2 二进制数据与十进制数据的关系
在二进制中,5表示为101,也就是5=1*pow(2,2)+1*pow(2,0)
1.3 正负数
在二进制中,需要有一个bit来表示是数据的正负,这bit就是数据的最高位。
1表示负数,0表示正数。
1.4 最大值和最小值
以int数据类型为例(下文中对于正数,如果位数没有足够的位数,笔者为了简单,会忽略高位的0,而从第一个1开始)
例如,int类型的5在计算机中的表达就是101。既然数据类型有字节数的限制,那么必然就会有该数据类型能够表达的范围。int类型的数据有32bits,因此最多能够表达的数字的个数就是2^32。
如果不考虑正负,那么32bits的数据能够表达的数据范围就是
00000…….000000(32个0)~11111……..1111111(32个1),也就是0到2^32-1。
但是1.2节讲到,数据有正负,因此在数据的表达范围就发生了变化。其真正的表达范围应该是
10000……000000(31个0)~011111……1111111(31个1)。也就是从 -2^31到2^31-1
看到这里,读者可能就有疑问了,为什么不是从00000……000000到1111111……1111111呢?
1.2中已经说过,最高位的1代表负数,0代表正数。因为000000……000000000代表0,最高位的0已经被占据了一位,那么剩下的31个bit能够表达的的数字也就是从0000……00000(31个0)到111111……11111(31个1),所以能够表达的就是从0到2^31-1。同理,对于负数的范围就是1000000……00000000到1111111……111111111,因此能够表达的就是从 -2^31到-1。
那么计算机中为什么是10000……0000000代表最小的值呢?
这其实是二进制的运算规则决定的。
例如,对于二进制的-1,其二进制的表达就是111111……111111,那么加1,就应该等于0(也就是0000000……000000)
所以,上面的-1的表达就是1111111111……111111111,按照这样的推算就可以知道最小数就是10000000……0000000000。
注:下面的部分会讲解相反数的计算,以及二进制数据的计算,这对于上面最大数最小数的表达的理解有帮助。
1.5 四则运算在二进制中的表达
那么,二进制是怎么进行计算的呢?
其实二进制和十进制的数据的计算规则也是一样的。
在十进制中,两个数相加的规则就是“逢十进一”,对于二进制同理,不过变成了“逢二进一”。相减就是如果被减数的位小于减数的位时,就向高位借1。
加法
规则:逢二进一
这里上面的1.3的例子已经很好的讲解了。那么这里还有一个问题,如果是按照逢二进一的规则,就会出现一种情况,就是最高位溢出的现象。也就是说最终计算出来的二进制数据超出了字节数的限制。那么应该将最高位的那个bit应该舍弃。
上面的1.3的例子就是一个很好的例证。
减法
规则:如果被减数的对应位置的数小于减数的上的数,那么就向其高位借2。简称”借一有二“
例如1-2=-1
即为:
00000……00001
- 00000……00010
——————————————11111……11111
乘法
由于二进制的乘法,每一位只有0和1,因此二进制的乘法更简单。
规则:
由低位到高位,用乘数的每一位去乘被乘数,若乘数的某一位为1,则该次部分积为被乘数;若乘数的某一位为0,则该次部分积为0。某次部分积的最低位必须和本位乘数对齐,所有部分积相加的结果则为相乘得到的乘积。
除法:
二进制数除法与十进制数除法很类似。
规则:先从被除数的最高位开始,将被除数(或中间余数)与除数相比较,若被除数(或中间余数)大于除数,则用被除数(或中间余数)减去除数,商为1,并得相减之后的中间余数,否则商为0。再将被除数的下一位移下补充到中间余数的末位,重复以上过程,就可得到所要求的各位商数和最终的余数。
1.6 相反数
二进制中,对于相反数的计算,就是”取反加1“
例如-1的相反数就是1。
在二进制中就是1111111……111111取反加1,得到00000……0000001。
2,位操作
二进制的位操作主要有移位、位与、或、异或、非。
其中,对于char,byte,short都是以转换为int进行移位操作的。而对于double和float都是没有位操作的。
2.1移位
移位操作符有两种,左移位<<和右移位>>,其中类似于+=这种操作符一样,也有<<=和>>=。
左移:
例如,5<<2表示5向左移动两位
5的二进制表示就是101,那么左移两位之后,就是10100,也就是乘以4即等于20。
对于位数左移之后,低位的补0。
那么比如10000……000000(即最小数),那么它左移2位之后,它的二进制表达就是00000000……000000(即为0)
public class BitCal {public static void main(String[] args) {int max_i=Integer.MIN_VALUE;System.out.println(Integer.toBinaryString(max_i));System.out.println(Integer.toBinaryString(max_i<<2));}
}
输出的结果为:
10000000000000000000000000000000
0
右移:
和左移不一样的地方就是:如果被位移的数是负数,那么右移之后,高位全都补1;如果是正数,那么右移之后,高位全都补0。也就是正数依然是正数,负数依然是负数。
无符号右移
这种移位操作与右移不同的地方就是:
无论是正数还是负数,在移位之后,高位都补0。即移位之后永远都是正数。
注:
(1)无论是左移还是右移(包括无符号右移),都有一个共同的规则。 如果移动的位数超过规定的bit数,都会与最大移位数取模之后进行计算。
例如:
int型,32bits,如果是5<<33,其实就是5<<1;同理,右移和无符号右移也是一样。
那么对于long型数据,也是一样。5<<65其实就是5<<1。
(2)对于byte和short进行移位运算的时候,他们会被转换为int型。进行右移的时候,因为精度的原因(byte和short本身比int字节少,因此转成int计算完毕,再转换回去的时候,可能会对高位截断)
这个例子,可以参考《Think in Java》中的例子
如下:
package operators;//: operators/URShift.java
// Test of unsigned right shift.
import static net.mindview.util.Print.print;public class URShift {public static void main(String[] args) {int i = -1;print(Integer.toBinaryString(i));i >>>= 10;print(Integer.toBinaryString(i));long l = -1;print(Long.toBinaryString(l));l >>>= 10;print(Long.toBinaryString(l));short s = -1;print(Integer.toBinaryString(s));s >>>= 10;print(Integer.toBinaryString(s));byte b = -1;print(Integer.toBinaryString(b));b >>>= 10;print(Integer.toBinaryString(b));b = -1;print(Integer.toBinaryString(b));print(Integer.toBinaryString(b>>>10));}
} /* Output:
11111111111111111111111111111111
1111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
1111111111111111111111
*///:~
笔者的疑惑
对于上面的第二条,《Think in Java》并没有提到char,只是说byte和short位移的时候,可能出现这种意外。但是对于char型数据,
利用如下测试代码:
package baisc.bit;public class BitCal {public static void main(String[] args) {char c1=(char)-1;System.out.println(Integer.toBinaryString(c1));c1>>=10;System.out.println(Integer.toBinaryString(c1));char c2=(char)-1;c2>>=17;System.out.println(Integer.toBinaryString(c2));char c3=(char)-1;c3>>=65;System.out.println(Integer.toBinaryString(c3));char u_c=(char)-1;u_c>>>=10;System.out.println(Integer.toBinaryString(u_c));short s=(short)-1;System.out.println(Integer.toBinaryString(s));s>>=33;System.out.println(Integer.toBinaryString(s));}
}
输出结果如下:
1111111111111111
111111
0
111111111111111
111111
11111111111111111111111111111111
11111111111111111111111111111111
所以,问题来了
1)为什么这里的第一个输出是16个1,而不是32个1,不是转换成int计算的么?
2)对于char类型的数据,右移和无符号右移都是高位补0么?
如果有读者了解这部分,希望能不吝赐教!
这里可能需要了解一下Integer类的toBinaryString()方法计算过程。
2.2 位与、或、异或、非
与:两个bit都为1的时候,结果为,否则为0
或:两个其中有一个为1即为1,否则为0
异或:相同为0,相异为1
非:0变1,1变0
3 &和&&、|和||的异同
对于boolean类型的数据,&和&&,|和||的计算结果相同。但是这里有一处区别,按位与和按位或需要操作计算两个二进制的计算结果。但是如果是逻辑或,逻辑与,会有短路效应。可能只需要根据其中一个条件就可以判断了,例如true||false只需要判断前面一个就可以了,false&&false就只需要判断前面一个就知道为false。
【Java】移位运算相关推荐
- 关于java移位运算的一点讨论
框架乱飞的年代,时常还得往框架源码里看,对内在原理没点理解,人家就会认为你不太行.平时开发你可能没咋用过位移运算,但往源码里一看,就时常能看到它.我也是看着看着,突然仔细一琢磨,又不由得发现自己基础知 ...
- java移位运算 cpu gpu_关于java操作中的移位运算
packagecom.dgjianke.ch03;/*** 关于二进制数据的一些操作 *@authordgjianke **/ public classBitManipulation {/*** 打印 ...
- Java移位运算之算术右移位
算术左移运算符 >>运算规则:按二进制形式把所有的数字向右移动对应巍峨位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1. 语法格式: 需要移位的数字 >> 移位 ...
- Java二进制位运算、移位运算、、
为什么80%的码农都做不了架构师?>>> Java二进制位运算.移位运算 思考题 1.请看下面的代码段,回答a,b,c,d,e结果是多少? public static void ...
- java逻辑移位和算术移位,关于对移位运算的理解
标签: 之前在<计算机组成原理>这门课中学习了很多,其中包括二进制数的移位运算.当时并不理解他们用来作甚,迷迷糊糊的状态,学了都不知道为什么要学.什么东西总是到了需要用到的时候,才明白,哦 ...
- Java从入门到精通08-二进制、位运算、移位运算
Java从入门到精通08-二进制.位运算.移位运算 二进制(Binary)数用0和1两个数字及其组合来表示任何数.进位规则是"逢2进1",数字1在不同的位上代表不同的值,按从右到左 ...
- Java中的位运算符、移位运算
一.位运算 Java中有4个位运算,它们的运算规则如下: (1)按位与 (&) :两位全为1,结果为1,否则为0: (2)按位或 (|) :两位有一个为1,结果为1,否则为0: (3) ...
- Java位运算之移位运算
文章目录 移位运算 左移 << 位运算符 右移 >> 位运算符 无符号右移 >>> 运算符 移位运算 移位运算符在程序设计中,是位操作运算符的一种.移位运算符 ...
- Java中的 移位 运算
Java中的 移位 运算 正数 左移 右移 无符号右移 负数 右移 无符号右移 左移 下面通过代码来演示: (在注释中 会标明 移位运算的 一些理论 ) public class Move {publ ...
最新文章
- Mybatis 使用的 9 种设计模式,真是太有用了
- 如何在VS2013配置CUDA,并编译生成DLL
- 工业安全的未来——IT与OT的融合
- 《WTM送书活动:向更遥远的星辰大海起航~》
- VS2015 Cordova Ionic移动开发(五)
- 【报告分享】“流量重构”时代来临,2020-2021中国消费互联网竞争趋势报告-腾讯.pdf(附下载链接)...
- h5下划线怎么设置_【Word技巧】毕业论文封面那条永远对不齐的下划线?
- ulipad.4.1.zip linux,Ubuntu 12.04下Ulipad的安装
- 联想计算机电源维修,自己动手修理联想X1 YOGA电源故障
- 天翼网关 ddns设置_超高并发服务网关架构设计与实现
- 计算机键盘的标点怎么打出来,电脑键盘上的标点符号怎么打(教你如何输入正确的标点符号)...
- WiFi通信字节乱码问题的产生原因及解决方法
- 快快云安全,网站被劫持怎么办
- 2023-04-18_面试题复盘笔记(121)
- 【转载】UEBA架构设计之路
- Vue3 - 组件通信(父传子)
- 树状数组再进阶(区间修改+区间查询)
- kaldi理解WFST,HCLG,lattice
- 什么是安全测试?一文教会你如何开展系统安全测试…
- Linux Shell 打开软件时最小化窗口
热门文章
- Sed 删除匹配行,匹配的字符用Shell变量替换,且变量里含有斜杠“/”时,无法删除 解决办法
- 什么是分布式,分布式和集群的区别又是什么?
- RK3399平台开发系列讲解(IIO子系统)4.43、IIO数据的获取方式介绍
- 基于SSM的学生信息管理系统的设计
- 10分钟构建人人都能学会的个性化聊天机器人-使用AIML(王小草博客)
- Ubuntu18.04提示adb设备没有权限
- Nginx配置文件中文详解
- 算法导论程序24--直接寻址表(Python)
- linux--- 连接数据库
- selenium自动化之登录淘宝自动下单案例