Java中处理二进制移位

我相信,这篇文章读起来会至关有趣。python

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

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

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

 1     public static String integerToBinaryString(int input) {
 2         char[] charr = new char[32];
 3         int k = 1;
 4         boolean isTrue;
 5         for (int i = 32 - 1; i >= 0; i--) {
 6             isTrue = (k & input) == k;
 7             charr[i] = isTrue ? '1' : '0';
 8             k = k << 1;
 9         }
10         return new String(charr);
11     }

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

调用如下方法:测试

1         int a = 9;// 1001
2         int b = 10;// 1010
3         System.out.println(integerToBinaryString(a | b));
4         System.out.println(integerToBinaryString(a ^ b));
5         System.out.println(integerToBinaryString(a & b));

输出结果:spa

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

code

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

 1         int a = 0x12345678;
 2         Scanner scanner = new Scanner(System.in);
 3         while (true) {
 4             System.out.println(integerToBinaryString(a));
 5             System.out.println(Integer.toHexString(a) + "\t" + a);
 6             System.out.print("输入:");
 7             String in = scanner.next();
 8             if (in.startsWith(">")) {
 9                 a >>= 1;
10             } else if (in.startsWith("<")) {
11                 a <<= 1;
12             } else if (in.startsWith("reset")) {
13                 Random rand = new Random();
14                 a = rand.nextInt();
15             } else {
16                 System.out.println("输入 '>'、'<' 或 'reset',请继续...");
17             }
18         }

 

控制台操做:图片

 

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

 

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

 

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

 

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

1 int b = -20;
2 int bb = ~b;
3 int bbb = ~b + 1;
4 System.out.println(integerToBinaryString(b));
5 System.out.println(integerToBinaryString(bb));
6 System.out.println(integerToBinaryString(bbb));

补码bbb和反码bb

 

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

有了这层意义,不妨定义一个运算的最大值为13a=7,b=-2a+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,固然这只是其中一点缘由,也许深入了解运算器构造和原理,对此问题会有个更好的认识。

相关文章
相关标签/搜索