我相信,这篇文章读起来会相当有趣。

文章中编程语言是Java,用Java的原因:
第一,Java不做数据溢出校验,这样我们可以忽略溢出异常;
第二,Java普及率比较高,就像是python或shell,几乎人人都会呐。

确定一些位运算符:
|   按位或   1001 | 1010 = 1011  (口诀,有真则真 似or逻辑)
^  按位异或  1001 ^ 1010 = 0011  (口诀,不等则真)
&  按位与   1001 & 1010 = 1000  (口诀,同真则真 似and逻辑)
~  按位取反  ~1001 = 0110 (这条没口诀)
>> 右移 或 位移除法
<< 左移 或 位移乘法

以下是一个将十进制数转化为二进制数显示为字符串的方法,为了方便我之后的测试而做此转换方法:

     public static String integerToBinaryString(int input) {
char[] charr = new char[32];
int k = 1;
boolean isTrue;
for (int i = 32 - 1; i >= 0; i--) {
isTrue = (k & input) == k;
charr[i] = isTrue ? '1' : '0';
k = k << 1;
}
return new String(charr);
}

此处我没有使用Integer.toBinaryString(n),是因为这个返回会忽略前面的所有零情况,二进制数据长度很难对齐,给分析带来很大难度。所以就自己做了integerToBinaryString方法,注意此方法从最低位开始计算每个位的值,因为我这里用Java写的测试,而Java是不支持无符号(unsigned)类型数据,有符号和无符号数据在 << 时规则是相同的,但是 >> 时,有符号和无符号会因最高位为符号位的限制,产生一些规则不同的问题,之后做个测试说明。

调用以下方法:

         int a = 9;//
int b = 10;//
System.out.println(integerToBinaryString(a | b));
System.out.println(integerToBinaryString(a ^ b));
System.out.println(integerToBinaryString(a & b));

输出结果:

以上结果用来验证我说的三个口诀,可见口诀正确。

请用以下代码进行测试位移:

         int a = 0x12345678;
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println(integerToBinaryString(a));
System.out.println(Integer.toHexString(a) + "\t" + a);
System.out.print("输入:");
String in = scanner.next();
if (in.startsWith(">")) {
a >>= 1;
} else if (in.startsWith("<")) {
a <<= 1;
} else if (in.startsWith("reset")) {
Random rand = new Random();
a = rand.nextInt();
} else {
System.out.println("输入 '>'、'<' 或 'reset',请继续...");
}
}

控制台操作:

由上位移可见,当a的最高位为1时(图片第四步骤),进行>>操作,最高位不会被0取代,继续进行操作:

通过<<操作将0推到最高位后,然后进行>>操作,最高位会被0覆盖。
以上简单的测试,只是为了解释一下在有符号位情况下,左移和右移操作的稍许不同之处,当然无符号情况下,最高位为1时,进行>>操作,最高位会被0覆盖。这是为什么呢?还是找一些官方解释比较有说服力。

这本教材是我大学里的必修课程,177页中位移除法对此有详细说明。

当然这个说法还是过于粗糙了,当了解了运算器对有符号位运算原理,或许就能豁然开朗了。
我还是说一些比较好玩的东西吧。
补码和反码

 int b = -20;
int bb = ~b;
int bbb = ~b + 1;
System.out.println(integerToBinaryString(b));
System.out.println(integerToBinaryString(bb));
System.out.println(integerToBinaryString(bbb));

补码bbb和反码bb

作为反码好理解点,就是按位翻转;
补码这东西总是让人云里雾里,有点琢磨不透,其实在二进制运算中,补码就是源码的模。
二进制中定义:正数补码是它本身,负数补码就是它的模了。

有了这层意义,不妨定义一个运算的最大值为13
a=7,b=-2
a+b==? 当然用简单运算的确能求出值为5
但是我要以以下方法求值
bb == b%13 == 11
这里要能理解 bb == b,否则很难解释下去了。
那么 a+b == a+bb == 7+11 == 18
因此时18大于13,超出部分会溢出,所以a+b == 18%13 == 5
跟我想当然理解 a+b == 7 +(-2) == 7-2 == 5 的值完全吻合
此时,无符号位移位除法空位设置0就很好理解,因为无符号的数一定都是非负数,其补码就是它本身;有符号位移位除法空位被设置为1估计也就好理解了,是为了方便此负数转补码时空位转为0,当然这只是其中一点原因,也许深刻了解运算器构造和原理,对此问题会有个更好的认识。

Java中处理二进制移位的更多相关文章

  1. Java中的二进制及基本的位运算

    Java中的二进制及基本的位运算 二进制是计算技术中广泛采用的一种数制.二进制数据是用0和1两个数码来表示的数.它的基数为2,进位规则是"逢二进一",借位规则是"借一当二 ...

  2. java中的二进制

    (1)按位与运算 & 1 & 1 = 1, 0 & 1 = 0 51 & 5  即 0011  0011 & 0000  0101 =0000 0001 = 1 ...

  3. 在Java中关于二进制、八进制、十六进制的辨析

    八进制数中不可能出7以上的阿拉伯数字.但如果这个数是123.是567,或12345670,那么它是八进制数还是10进制数?单从数字的角度来讲都有可能! 八进制 所以在Java中规定,一个数如果要指明它 ...

  4. java中表示二进制、八进制、十进制、十六进制,double、float、整型

    java里不能这样表示二进制,只能是   8,10,16进制  8:         前置   0  10:      不需前置 16:      前置   0x   或者   0X double:2 ...

  5. java中表示二进制、八进制、十进制、十六进制

    1.进制 进制是一种记数方式 ,可以用有限的数字符号代表所有的数值.由特定的数值组成. 2.进制的表现形式 二进制: 由0和1两个数字组成. 八进制: 由0-7数字组成,为了区分与其他进制的数字区别, ...

  6. java中关于二进制的初步。

    两个int型和一个long型的转换: long now=1368257088802L;                  int low = (int) (0xFFFFFFFFL & now) ...

  7. java中使用二进制进行权限控制

    基本概念 package test; publicclass Rights { publicstaticvoid main(String[] args) { int a=1; // 001 状态a i ...

  8. Java中转换为二进制的几种实现

    public class HexUtil { private static final String[] DIGITS_UPPER = {"0", "1", & ...

  9. java中的进制与操作符

    直接常量 double: 111d,111D 二进制:前缀为0b 十六进制:前缀为0x或0X,后面最大9位. 八进制:前缀为0,后面最大7位. 按位操作符 与(&): 或(||): 异或(^) ...

随机推荐

  1. 模拟在内存中的数据库DataSet相关的类

    这篇连着上一篇DataReader相关类. 下面两段话是在msdn官网摘下来:       .NET Framework 数据提供程序是专门为数据操作以及快速.只进.只读访问数据而设计的组件.Conn ...

  2. MySQL二进制日志总结

    二进制日志简单介绍 MySQL的二进制日志(binary log)是一个二进制文件,主要用于记录修改数据或有可能引起数据变更的MySQL语句.二进制日志(binary log)中记录了对MySQL数据 ...

  3. java学习笔记 --- 集合

    1.定义:集合是一种容器,专门用来存储对象 数组和集合的区别?   A:长度区别  数组的长度固定 集合长度可变 B:内容不同  数组存储的是同一种类型的元素  而集合可以存储不同类型的元素  C:元 ...

  4. FastDFS分布文件系统相关资料索引

    FastDFS是为互联网应用量身定做的一套分布式文件存储系统,非常适合用来存储用户图片.视频.文档等文件.对于互联网应用,和其他分布式文件系统相比,优势非常明显.具体情况大家可以看相关的介绍文档,包括 ...

  5. pyqt样式表语法笔记(中)--原创

    pyqt样式表语法笔记(中) pyqt QSS python 样式表 一.弹窗 在日常的各种桌面软件的使用中,我们都会碰到弹窗.例如注册,登录的时候,会有相应的信息弹窗,这里就以信息收集弹窗为例进行弹 ...

  6. 当Node.js遇见Docker

    Node.js Best Practices - How to Become a Better Developer in 2017提到的几点,我们Fundebug深有同感: 使用ES6 使用Promi ...

  7. Excel 按模板格式导出

    最近遇到一个问题,就是导出数据的时候需要自定义的表头,如图 如果自己用代码写表头的话,可能会有点复杂,而且代码量很多,所以我就想了一个办法,直接在Excel里面把表头定义好,然后把数据写入Excel模 ...

  8. Python javascript操作DOM

    文档对象模型(Document Object Model,DOM)是一种用于HTML和XML文档的编程接口.它给文档提供了一种结构化的表示方法,可以改变文档的内容和呈现方式.我们最为关心的是,DOM把 ...

  9. iOS开发 - 啰嗦讲解 Runloop

    写在前面的 为什么要了解 RunLoop?如果你想成为一个高级iOS开发工程师,那这是你必须了解的东西,他能帮助你更好的理解底层实现的原理,可以利用它的特性做出一些高效又神奇的功能.RunLoop这个 ...

  10. 实现简单的跨站脚本攻击(XSS)

    我们来通俗的了解一下什么是跨站脚本攻击(XSS):在表单中提交 一段 js代码 ,提交的内容被展示到页面时 ,js会被浏览器解析 打个比方吧,比如我现在写的这篇博客,写完以后我要发表对吧? 发表这个过 ...