二进制

什么是二进制(可自行下载演示工具)

逢二进一的计数规则
2进制是成本最优方案

int i = 50;
// “50” -> 00000000 00000000 00000000 00110010 -> i
System.out.println(i);//110010 -> “50”
//Integer.toBinaryString(i) 将i的内存2进制,显示出来
//输出时候, Java会省略高位的0
System.out.println(Integer.toBinaryString(i)); //110010
long n = 123;
System.out.println(Long.toBinaryString(n));
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000100
00000000 00000000 00000000 00000101
00000000 00000000 00000000 00000110
00000000 00000000 00000000 00000111
00000000 00000000 00000000 00001000
00000000 00000000 00000000 00001001
00000000 00000000 00000000 00001010
00000000 00000000 00000000 00001011
00000000 00000000 00000000 00001100
00000000 00000000 00000000 00001101
00000000 00000000 00000000 00001110

00000000 00000000 00000000 10001101 = 128+8+4+1 = 141
00000000 00000000 00000000 01100010 = 64+32+2 = 98
在这里插入图片描述
在这里插入图片描述

16进制

2进制书写繁琐!

计算机专家发现16进制可以用于缩写2进制

由于基数16是2的4次幂
将2进制从低位到高位,每4位2进制可以缩写为1位16进制.

public class Demo03 {
    public static void main(String[] args) {
        /**
         * Java 7 (JDK1.7) 开始支持0b开头的2进制直接量
         * 
         * 2进制书写繁琐!
         */
        int n = 0b110010;
        System.out.println(n); 
        n = 0b00010011_11110100_11110010_11111101; 
        //    1   3    f   4    f   2    f   d
        int k = 0x13f4f2fd;
        System.out.println(Integer.toBinaryString(n)); 
        System.out.println(Integer.toBinaryString(k)); 
        
        System.out.println(n);
        //00010011_11110100_11110010_11111101 -> "334820093"
    }
}

在这里插入图片描述

手工计算负数补码的值:

11111111111111111111111111111111 = -1

11111111111111111111111111011101
11111111111111111111111111011110
11111111111111111111111111011111
11111111111111111111111111100000
11111111111111111111111111100001
11111111111111111111111111100010 = -1-1-4-8-16 = -30
11111111111111111111111111100011
11111111111111111111111111100100
11111111111111111111111111100101 = -1-2-8-16 = -27
在这里插入图片描述

案例

public class Demo06 {

public static void main(String[] args) {
/*
* 验证补码的互补对称
* -n = ~n + 1, 最小值除外
/
int n = -80;
int m = ~n + 1;
System.out.println(m); //80
System.out.println(Integer.toBinaryString(n));
System.out.println(Integer.toBinaryString(~n));
System.out.println(Integer.toBinaryString(~n+1));
/
*
* 11111111111111111111111110110000 = -1-1-2-4-8-64=-80
00000000000000000000000001001111 = 1+2+4+8+64 = 79
00000000000000000000000001010000 = 16+64 = 80
*/

经典面试题目:

如下代码的输出结果: ( C )

System.out.println(~80+1); A.-78 B.-79 C.-80 D.-81

如下代码的输出结果: ( D )

System.out.println(~80); A.-78 B.-79 C.-80 D.-81

如下代码的输出结果: ( B )

System.out.println(~-80); A.78 B.79 C.80 D.81

2进制运算

运算符号
~ 取反
|&>>> 右移位
>> 数学右移位
<< 左移位

与运算 & (and)

运算规则: 逻辑乘法, 有0则0

0 & 0 -> 0
0 & 1 -> 0
1 & 0 -> 0
1 & 1 -> 1

运算时候将两个数对其位数, 对应位置进行与计算:

                  7   b    8   f    d   f    6   a    
n  =        01111011 10001111 11011111 01101010 
m  =        00000000 00000000 00000000 11111111 掩码(mask)
k = n & m   00000000 00000000 00000000 01101010

如上计算的意义: 称为掩码计算, 经过8位掩码计算, 将n的最后8位数截取保存到k中. 从最低位到最高位1的个数称为掩码的位数.

代码:

int n = 0x7b8fdf6a;
int m = 0xff;
int k = n & m;
System.out.println(Integer.toBinaryString(n));
System.out.println(Integer.toBinaryString(m));
System.out.println(Integer.toBinaryString(k));

右移位计算 >>>
运算规则: 将数字的整体向右移动, 低位自动溢出,高位补0

**将一个int拆分为4个字节**
               b1       b2       b3       b4
n  =        01111011 10001111 11011111 01101010 
b1 =        00000000 00000000 00000000 01111011
b2 =        00000000 00000000 00000000 10001111
b3 =        00000000 00000000 00000000 11011111
b4 =        00000000 00000000 00000000 01101010

b1 = (n>>>24) & 0xff;
b2 = (n>>>16) & 0xff;
b3 = (n>>>8) & 0xff;
b4 = n & 0xff;
举个例子:

n  =        01111011 10001111 11011111 01101010 
m = n>>>1   001111011 10001111 11011111 0110101 
k = n>>>2   0001111011 10001111 11011111 011010
g = n>>>8   00000000 01111011 10001111 11011111  
b3= (n>>>8) & 0xff
代码:

int n = 0x7b8fdf6a;
int m = n>>>1;
int k = n>>>2;
int g = n>>>8;
int b3 = (n>>>8) & 0xff;

左移位计算 <<

规则:将数字的整体向左移动, 高位会溢出舍弃, 低位补0. 高位可能会溢出到符号位, 溢出到符号位时候, 会出现正数变负数.

举个栗子:

n =      01011101 11001000 10001111 10110101
m=n<<1   1011101 11001000 10001111 101101010
k=n<<2   011101 11001000 10001111 1011010100
g=n<<8   11001000 10001111 10110101 00000000

将四个字节 b1 b2 b3 b4 合并为一个int

b1 =        00000000 00000000 00000000 01111011
b2 =        00000000 00000000 00000000 10001111
b3 =        00000000 00000000 00000000 11011111
b4 =        00000000 00000000 00000000 01101010 
               b1       b2       b3       b4    
n  =        01111011 10001111 11011111 01101010 
b1<<24      01111011 00000000 00000000 00000000 
b2<<16      00000000 10001111 00000000 00000000 
b3<<8       00000000 00000000 11011111 00000000 
b4 =        00000000 00000000 00000000 01101010 
n = (b1<<24) | (b2<<16) | (b3<<8) | b4

代码:

int b1 = 0x7b, b2 = 0x8f, b3 = 0xdf, b4 = 0x6a;
int n = (b1<<24) | (b2<<16) | (b3<<8) | b4;

移位计算的数学意义

将2进制数字向左移动, 每移动一次数字乘以2, 可能发生溢出

将2进制数字向右移动, 每移动一次数字除以2, 可以发生溢出, 小方向取整数

public class Demo08 {public static void main(String[] args) {
        /*
         * 移位计算数学意义
         */
        int n = 50;
        System.out.println(n<<1); 
        System.out.println(n<<2); 
        System.out.println(n<<3); 
        System.out.println(n<<4); 
        System.out.println(n>>1); 
        System.out.println(n>>2); 
        System.out.println(n>>3); 
    }}

经典面试题目:
将表达式 n*8 替换为 ( n<<3 )

将表达式 n/2 替换为 ( n>>1 )

数学右移位 >>

**>>>**称为逻辑右移位, 将数字每个位向右移动, 无论正数还是负数高位补0, 单纯的将数字整体向右移动, 不考虑数学结果(不考虑符号位)

称为数学右移位, 将数字每个位向右移动, 高位为1时候(负数), 高位补1, 高位为0时候(正数), 高位补0. >> 保持了符号位不变, 结果是数学除2,向小方向取整数.
举个例:

n   =   11111111 11111111 11111111 11001110 =-1-1-16-32=-50
m=n>>1  111111111 11111111 11111111 1100111 =-1-8-16=-25
k=n>>2  1111111111 11111111 11111111 110011 =-1-4-8=-13
g=n>>>1 011111111 11111111 11111111 1100111 =max-24

选择:

如果仅仅为了将数字向右移动, 就选择 >>>
如果是为了适当替换数学除法运算, 选择 >>

public class Demo08 {public static void main(String[] args) {
        /*
         * 移位计算数学意义
         */
        int n = 50;
        System.out.println(n<<1); 
        System.out.println(n<<2); 
        System.out.println(n<<3); 
        System.out.println(n<<4); 
        System.out.println(n>>1); 
        System.out.println(n>>2); 
        System.out.println(n>>3); 
    }}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值