什么是2进制
逢2进1的计数规则.
案例:
1 public class Demo01 { 2 3 public static void main(String[] args) { 4 /** 5 * 第一次 看见2进制 6 */ 7 int i = 50; //110010 8 //在println(i)输出时候,Java会使用 9 //API(方法)将2进制转换为10进制字符串 10 System.out.println(i); //"50" 11 //Java提供了方法toBinaryString可以 12 //看到内存中存储的2进制数据 13 System.out.println( 14 Integer.toBinaryString(i)); 15 for(i=0; i<=50; i++) { 16 System.out.println( 17 Integer.toBinaryString(i)); 18 } 19 20 } 21 }
计算机和2进制的关系
16进制
16进制用于简写(缩写)2进制. 因为2进制书写冗长\麻烦\易错, 因为16进制基数是2的整次幂, 所以4位2进制可以缩写为一个16进制数字.
缩写规则: 将2进制从后向前,每4位2进制数缩写为一个16进制.
案例:
1 public static void main(String[] args) { 2 /** 3 * 直接书写2进制, Java 7 以后支持的 4 * 特性, 可以以0b开头书写2进制数据 5 */ 6 int n = 0b110010; 7 System.out.println(n); 8 9 //2进制书写麻烦 10 n = 0b11010011111101010010111101; 11 //16进制简写2进制, 使用起来方便 12 13 int i = 0x77a65fa8; 14 System.out.println( 15 Integer.toBinaryString(i)); 16 }
补码
计算机中的一种解决负数(有符号数)问题的编码, 其核心目的是将固定位数的2进制数,分一半作为负数.
补码是如何将固定位数的2进制分一半作为负数的?
以4位2进制为例讲解补码编码规则:
- 计算时候, 超过4位时候自动溢出舍弃, 保持数字始终是4位2进制数.
- 高位为1的作为负数, 高位为0的作为整数
- 负数编码由正数反向推算出来.
- 负数与正数正好互补对称: 顾称为补码.
案例1
1 public static void main(String[] args) { 2 /** 3 * 补码 4 */ 5 int n = -13; 6 System.out.println(Integer.toBinaryString(n)); 7 for(int i=-50; i<0; i++) { 8 System.out.println( 9 Integer.toBinaryString(i)); 10 } 11 }
案例2: 特殊值
1 public static void main(String[] args) { 2 int max = Integer.MAX_VALUE; 3 int min = Integer.MIN_VALUE; 4 System.out.println(max); 5 System.out.println(min); 6 System.out.println(Integer.toBinaryString(max)); 7 System.out.println(Integer.toBinaryString(min)); 8 //int n = -1; 9 //int n = 0b11111111111111111111111111111111; 10 int n = 0xffffffff; 11 System.out.println(Integer.toBinaryString(n)); 12 System.out.println(n); //按照10进制输出:-1 13 //溢出结果: 可能是正数也可能是负数! 14 int k = 100; 15 System.out.println(k+max); 16 System.out.println(k+max+max); 17 //如上运算结果说明 补码是一个环形编码! 18 }
补码的互补对称性:
计算原理:
n 00000000 00000000 00000000 00110010 50 ~n 11111111 11111111 11111111 11001101 -51 ~n+1 11111111 11111111 11111111 11001110 -50
互补对称实验案例:
1 int n = 50; 2 int m = ~n + 1; 3 System.out.println(m);//-50 4 System.out.println(Integer.toBinaryString(n)); 5 System.out.println(Integer.toBinaryString(~n)); 6 System.out.println(Integer.toBinaryString(~n+1));
经典面试题目:
System.out.println(~5); 如上代码的输出结果:( D ) A.5 B.6 C.-5 D.-6 System.out.println(~-5); 如上代码的输出结果:( A ) A.4 B.5 C.6 D.7
2进制运算
运算符号:
~ 取反 & 与 | 或 >> 右移位 >>> 逻辑右移位 << 左移位
&与计算(逻辑乘法)
基本规则: 有0则为0
0 & 0 = 0 0 & 1 = 0 1 & 0 = 0 1 & 1 = 1
计算时候,需要将两个数字对其位数, 对应位置数字计算与运算:
举个栗子:
n = 01110111 01010100 10111111 11110111 m = 00000000 00000000 00000000 11111111 mask k=n&m 00000000 00000000 00000000 11110111
如上计算的意义: 如上是掩码(Mask)计算(拆分计算), 其拆分结果 k 是 n 的最后8位(1字节)
实验
int n = 0x7754bff7; int m = 0xff; //8位掩码(Mask): 1的个数有8个 int k = n&m; //按照2进制验证结果 System.out.println(Integer.toBinaryString(n)); System.out.println(Integer.toBinaryString(m)); System.out.println(Integer.toBinaryString(k));
>>>
逻辑右移位计算
将2进制数位整体向右移位, 低位自动溢出, 高位补0:
案例:
1 public static void main(String[] args) { 2 /** 3 * 移位计算案例 4 */ 5 int n = 0x7754bff7; 6 int m = n>>>1; 7 int k = n>>>2; 8 int g = n>>>8; 9 int b3 = (n>>>8) & 0xff; 10 System.out.println(Integer.toBinaryString(n)); 11 System.out.println(Integer.toBinaryString(m)); 12 System.out.println(Integer.toBinaryString(k)); 13 System.out.println(Integer.toBinaryString(g)); 14 System.out.println(Integer.toBinaryString(b3)); 15 }
拆分整数为byte
案例:
1 public static void main(String[] args) { 2 /** 3 * 将一个整数int拆分为4个byte 4 * 案例: 将一个整数long拆分为8个byte 5 */ 6 int n = 0x7745abd7; 7 int b1 = (n>>>24) & 0xff; 8 int b2 = (n>>>16) & 0xff; 9 int b3 = (n>>>8) & 0xff; 10 int b4 = n & 0xff; 11 System.out.println(Integer.toBinaryString(n)); 12 System.out.println(Integer.toBinaryString(b1)); 13 System.out.println(Integer.toBinaryString(b2)); 14 System.out.println(Integer.toBinaryString(b3)); 15 System.out.println(Integer.toBinaryString(b4)); 16 /** 17 * 将一个整数long拆分为8个byte 18 */ 19 long l = 0x76ab3fed723e7828L; 20 b1 = (int)((l>>>56)& 0xff); 21 b2 = (int)((l>>>48)& 0xff); 22 b3 = (int)((l>>>40)& 0xff); 23 b4 = (int)((l>>>32)& 0xff); 24 int b5 = (int)((l>>>24)& 0xff); 25 int b6 = (int)((l>>>16)& 0xff); 26 int b7 = (int)((l>>>8)& 0xff); 27 int b8 = (int)((l>>>0)& 0xff); 28 //验证... 29 System.out.println(Long.toBinaryString(l)); 30 }
| 或运算(逻辑加法)
基本规则: 有1则1
0 | 0 = 0 0 | 1 = 1 1 | 0 = 1 1 | 1 = 1
计算时候, 将两个数的数位对齐对应位进行或计算.
举个栗子:
n= 00000000 00000000 00000000 10011101 m= 00000000 00000000 11011111 00000000 k=n|m 00000000 00000000 11011111 10011101
如上计算意义: 将n和m两个数字进行拼接计算.
验证:
int n = 0x9d; int m = 0xdf00; int k = n|m; //按照2进制输出
<< 左移位
将2进制数字每个位向左移动, 高位溢出, 低位补0
移位计算的数学意义
回顾10进制小数点移动计算:
// 89191. // 891910. // 8919100. // 10进制时候, 数字向左移动一次, 数值扩展10倍 // 110010. 50 // 1100100. 100 = 50<<1 // 11001000. 200 = 50<<2 // 2进制时候, 数字向左移动一次, 数值扩大2倍 // 110010. 50 // 11001. 25 = 50>>1 // 1100. 12 = 50>>2 向小方向取整数
案例:
/** * 移动计算的数学意义 */ int n = 50; System.out.println(n); System.out.println(n<<1); System.out.println(n<<2); System.out.println(n<<3); System.out.println(n>>1); System.out.println(n>>2);
>> >>> 的区别
>>
称为数学右移位计算, 当正数时候(高位为0), 高位补0, 当负数时候(高位为1) 高位补1, 其运算结果是数学除法, 向小方向取整.
>>>
称为逻辑右移位计算, 无论正负高位都补0, 负数时候不符合数学运算结果
举个栗子:
n = 11111111 11111111 11111111 11001110 -50 m=n>>1 111111111 11111111 11111111 1100111 -25 g=n>>2 1111111111 11111111 11111111 110011 -13 k=n>>>1 011111111 11111111 11111111 1100111 比最大值小24
>>
运算是接近数学结果: 除以2向小方向取整数.
>>>
单纯将数位向右移动, 其结果不考虑数学意义, 进行数字拆分合并时候采用纯正的右移动.
面试案例: 替代2的整数倍乘法, 使用采用数学移位!
n * 32 可以替换为 ( n<<5 ) n / 2 (n>=0) 可以替换为 ( n>>1 )
来源:https://www.cnblogs.com/hello4world/p/12094379.html