以前一直没有研究二进制的移位运算的应用场景是什么,怎么运算?怎么实现数据的四则运算的? 直到最近,在看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】移位运算相关推荐

  1. 关于java移位运算的一点讨论

    框架乱飞的年代,时常还得往框架源码里看,对内在原理没点理解,人家就会认为你不太行.平时开发你可能没咋用过位移运算,但往源码里一看,就时常能看到它.我也是看着看着,突然仔细一琢磨,又不由得发现自己基础知 ...

  2. java移位运算 cpu gpu_关于java操作中的移位运算

    packagecom.dgjianke.ch03;/*** 关于二进制数据的一些操作 *@authordgjianke **/ public classBitManipulation {/*** 打印 ...

  3. Java移位运算之算术右移位

    算术左移运算符 >>运算规则:按二进制形式把所有的数字向右移动对应巍峨位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1. 语法格式: 需要移位的数字 >> 移位 ...

  4. Java二进制位运算、移位运算、、

    为什么80%的码农都做不了架构师?>>>    Java二进制位运算.移位运算 思考题 1.请看下面的代码段,回答a,b,c,d,e结果是多少? public static void ...

  5. java逻辑移位和算术移位,关于对移位运算的理解

    标签: 之前在<计算机组成原理>这门课中学习了很多,其中包括二进制数的移位运算.当时并不理解他们用来作甚,迷迷糊糊的状态,学了都不知道为什么要学.什么东西总是到了需要用到的时候,才明白,哦 ...

  6. Java从入门到精通08-二进制、位运算、移位运算

    Java从入门到精通08-二进制.位运算.移位运算 二进制(Binary)数用0和1两个数字及其组合来表示任何数.进位规则是"逢2进1",数字1在不同的位上代表不同的值,按从右到左 ...

  7. Java中的位运算符、移位运算

    一.位运算 Java中有4个位运算,它们的运算规则如下: (1)按位与 (&)  :两位全为1,结果为1,否则为0: (2)按位或  (|)   :两位有一个为1,结果为1,否则为0: (3) ...

  8. Java位运算之移位运算

    文章目录 移位运算 左移 << 位运算符 右移 >> 位运算符 无符号右移 >>> 运算符 移位运算 移位运算符在程序设计中,是位操作运算符的一种.移位运算符 ...

  9. Java中的 移位 运算

    Java中的 移位 运算 正数 左移 右移 无符号右移 负数 右移 无符号右移 左移 下面通过代码来演示: (在注释中 会标明 移位运算的 一些理论 ) public class Move {publ ...

最新文章

  1. Mybatis 使用的 9 种设计模式,真是太有用了
  2. 如何在VS2013配置CUDA,并编译生成DLL
  3. 工业安全的未来——IT与OT的融合
  4. 《WTM送书活动:向更遥远的星辰大海起航~》
  5. VS2015 Cordova Ionic移动开发(五)
  6. 【报告分享】“流量重构”时代来临,2020-2021中国消费互联网竞争趋势报告-腾讯.pdf(附下载链接)...
  7. h5下划线怎么设置_【Word技巧】毕业论文封面那条永远对不齐的下划线?
  8. ulipad.4.1.zip linux,Ubuntu 12.04下Ulipad的安装
  9. 联想计算机电源维修,自己动手修理联想X1 YOGA电源故障
  10. 天翼网关 ddns设置_超高并发服务网关架构设计与实现
  11. 计算机键盘的标点怎么打出来,电脑键盘上的标点符号怎么打(教你如何输入正确的标点符号)...
  12. WiFi通信字节乱码问题的产生原因及解决方法
  13. 快快云安全,网站被劫持怎么办
  14. 2023-04-18_面试题复盘笔记(121)
  15. 【转载】UEBA架构设计之路
  16. Vue3 - 组件通信(父传子)
  17. 树状数组再进阶(区间修改+区间查询)
  18. kaldi理解WFST,HCLG,lattice
  19. 什么是安全测试?一文教会你如何开展系统安全测试…
  20. Linux Shell 打开软件时最小化窗口

热门文章

  1. Sed 删除匹配行,匹配的字符用Shell变量替换,且变量里含有斜杠“/”时,无法删除 解决办法
  2. 什么是分布式,分布式和集群的区别又是什么?
  3. RK3399平台开发系列讲解(IIO子系统)4.43、IIO数据的获取方式介绍
  4. 基于SSM的学生信息管理系统的设计
  5. 10分钟构建人人都能学会的个性化聊天机器人-使用AIML(王小草博客)
  6. Ubuntu18.04提示adb设备没有权限
  7. Nginx配置文件中文详解
  8. 算法导论程序24--直接寻址表(Python)
  9. linux--- 连接数据库
  10. selenium自动化之登录淘宝自动下单案例