二进制及运算
二进制
基本介绍
符号位概念:最高位为符号位,0 表示正数,1 表示负数
(1)给一个负数,如果求该负数的二进制?
先求该负数对应的正数的二进制,减一,取反

(2)给一个负数的二进制,如何知道是负几?
将二进制取反,加一,得到的二进制的值就是负数的绝对值

范围问题

问题一:如何理解对于有 n 位的二进制数,可以表示的数的个数位 2ⁿ ?
每位二进制有 0 和 1 两种选择,n 位就是 n 个 2 相乘,即 2ⁿ 种组合,对应 2ⁿ 个不同的数
问题二:范围的右边界为什么是 2ⁿ - 1 ?
(1)第一种理解
一共有 2ⁿ 个不同的数,而无符号数是从 0 开始的,0 占用了一位,所以范围的右边界是 2ⁿ - 1
(2)第二种理解
利用等比数列的求和公式,结果即是 2ⁿ - 1

相反数
无论是正数还是负数,相反数 = 当前数取反 + 1
位运算
(1)按位 &:两位全为 1,结果为 1,否则为 0
(2)按位或 |:两位有一个为 1,结果为 1,否则为 0
(3)按位取反 ~:0 - > 1 , 1 - > 0
(4)按位异或 ^:两位一个为 0,一个为 1,结果为 1,否则为 0
(5)算术左移 <<:无论正数、负数,低位都是补 0
(6)算术右移 >>:正数:高位补 0,负数:高位补 1
(7)无符号右移 >>>:无论正数、负数,高位都是补 0
如何打印二进制
核心关系式:(num &(1 << i)) == 0 ? "0" : "1",i 表示该数有多少个 bit 位
本节代码
java
package class003;
// 本文件的实现是用int来举例的
// 对于long类型完全同理
// 不过要注意,如果是long类型的数字num,有64位
// num & (1 << 48),这种写法不对
// 因为1是一个int类型,只有32位,所以(1 << 48)早就溢出了,所以无意义
// 应该写成 : num & (1L << 48)
public class BinarySystem {
// 打印一个int类型的数字,32位进制的状态
// 左侧是高位,右侧是低位
public static void printBinary(int num) {
for (int i = 31; i >= 0; i--) {
// 下面这句写法,可以改成 :
// System.out.print((a & (1 << i)) != 0 ? "1" : "0");
// 但不可以改成 :
// System.out.print((a & (1 << i)) == 1 ? "1" : "0");
// 因为a如果第i位有1,那么(a & (1 << i))是2的i次方,而不一定是1
// 比如,a = 0010011
// a的第0位是1,第1位是1,第4位是1
// (a & (1<<4)) == 16(不是1),说明a的第4位是1状态
System.out.print((num & (1 << i)) == 0 ? "0" : "1");
}
System.out.println();
}
public static void main(String[] args) {
// 非负数
int a = 78;
System.out.println(a);
printBinary(a);
System.out.println("===a===");
// 负数
int b = -6;
System.out.println(b);
printBinary(b);
System.out.println("===b===");
// 直接写二进制的形式定义变量
int c = 0b1001110;
System.out.println(c);
printBinary(c);
System.out.println("===c===");
// 直接写十六进制的形式定义变量
// 0100 -> 4
// 1110 -> e
// 0x4e -> 01001110
int d = 0x4e;
System.out.println(d);
printBinary(d);
System.out.println("===d===");
// ~、相反数
System.out.println(a);
printBinary(a);
printBinary(~a);
int e = ~a + 1;
System.out.println(e);
printBinary(e);
System.out.println("===e===");
// int、long的最小值,取相反数、绝对值,都是自己
int f = Integer.MIN_VALUE;
System.out.println(f);
printBinary(f);
System.out.println(-f);
printBinary(-f);
System.out.println(~f + 1);
printBinary(~f + 1);
System.out.println("===f===");
// | & ^
int g = 0b0001010;
int h = 0b0001100;
printBinary(g | h);
printBinary(g & h);
printBinary(g ^ h);
System.out.println("===g、h===");
// 可以这么写 : int num = 3231 | 6434;
// 可以这么写 : int num = 3231 & 6434;
// 不能这么写 : int num = 3231 || 6434;
// 不能这么写 : int num = 3231 && 6434;
// 因为 ||、&& 是 逻辑或、逻辑与,只能连接boolean类型
// 不仅如此,|、& 连接的两侧一定都会计算
// 而 ||、&& 有穿透性的特点
System.out.println("test1测试开始");
boolean test1 = returnTrue() | returnFalse();
System.out.println("test1结果," + test1);
System.out.println("test2测试开始");
boolean test2 = returnTrue() || returnFalse();
System.out.println("test2结果," + test2);
System.out.println("test3测试开始");
boolean test3 = returnFalse() & returnTrue();
System.out.println("test3结果," + test3);
System.out.println("test4测试开始");
boolean test4 = returnFalse() && returnTrue();
System.out.println("test4结果," + test4);
System.out.println("===|、&、||、&&===");
// <<
int i = 0b0011010;
printBinary(i);
printBinary(i << 1);
printBinary(i << 2);
printBinary(i << 3);
System.out.println("===i << ===");
// 非负数 >> >>>,效果一样
printBinary(i);
printBinary(i >> 2);
printBinary(i >>> 2);
System.out.println("===i >> >>>===");
// 负数 >> >>>,效果不一样
int j = 0b11110000000000000000000000000000;
printBinary(j);
printBinary(j >> 2);
printBinary(j >>> 2);
System.out.println("===j >> >>>===");
// 非负数 << 1,等同于乘以2
// 非负数 << 2,等同于乘以4
// 非负数 << 3,等同于乘以8
// 非负数 << i,等同于乘以2的i次方
// ...
// 非负数 >> 1,等同于除以2
// 非负数 >> 2,等同于除以4
// 非负数 >> 3,等同于除以8
// 非负数 >> i,等同于除以2的i次方
// 只有非负数符合这个特征,负数不要用
int k = 10;
System.out.println(k);
System.out.println(k << 1);
System.out.println(k << 2);
System.out.println(k << 3);
System.out.println(k >> 1);
System.out.println(k >> 2);
System.out.println(k >> 3);
System.out.println("===k===");
}
public static boolean returnTrue() {
System.out.println("进入了returnTrue函数");
return true;
}
public static boolean returnFalse() {
System.out.println("进入了returnFalse函数");
return false;
}
}