2进制

本秂侑毒 提交于 2019-12-25 01:01:20

什么是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进制为例讲解补码编码规则:

  1. 计算时候, 超过4位时候自动溢出舍弃, 保持数字始终是4位2进制数.
  2. 高位为1的作为负数, 高位为0的作为整数
  3. 负数编码由正数反向推算出来.
  4. 负数与正数正好互补对称: 顾称为补码.

案例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 )

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!