算法第一节课程
package class01;
public class Code01_PrintBinary {
public static void print(int num) {//打印整数在内存中的32位二进制信息,java中整型都是有符号整型。直接打印是打印函数将二进制转换成了十进制而已。
for (int i = 31; i >= 0; i--) {
System.out.print((num & (1 << i)) == 0 ? "0" : "1");
/*二进制中左移多少位,就乘以2的多少次方,
右移多少位就除以2的多少次方,剩下的位置用零补上。
===》可以类推其他进制,相应地乘或者除多少进制的次方。
其实一个整数数在计算机底层是二进制代码表示的,与运算符"&"出现时,
只有两个数的每一位都是1才输出一,有一个是零相与的结构就是0;
1位移多少位与num相应的位相与,输出的数都是num原来位上的数字,
下面总是0 & 1=0,1 & 1=1;此函数从最高位依次打印,
不换行打印的结果就是此整数在内存中的二进制表示方法。位移操作可以见main方法中的
//可以看以下的一些效果,即可明白位移操作,相应的右移是一样的操作,
===》可以类推其他进制,相应地乘或者除多少进制的次方。八进制、十六进制
需要打印某一位的值,让num & (1左移多少位,剩下的全是0补齐)。
int test = 1;
print(test);
print(test<<1);
print(test<<2);
print(test<<8);
*/
}
System.out.println();
}
public static void main(String[] args) {
// 32位 java中int是四个字节32位
// int num = 4;
//
// print(num);
//
//
// int test = 1123123;
// print(test);
// print(test<<1);
// print(test<<2);
// print(test<<8);
//
//
// print(0);
// int a = Integer.MAX_VALUE;//理论上最大值是42亿多
// print(a);
// System.out.println(a);//程序验证最大值仅有21亿多,十进制打印
/*
程序验证最大值仅有21亿多,底层是把最高位用作符号位(仅仅针对有符号整数4字节)
java整数就是有符号整数,既可以表示正数,也可以表示负数。整数1在内存中表示
的就是最低位为1,前面高位31位都是0;以下仅针对四字节的int类型
C++里面无符号整数,整型32位都用来表示数字,最高位不用来表示符号位,所以
C++里面最大的数就是 0 ~ 2的32次方减 1;故有符号最大值不如无符号最大值大!
无符号整数表示范围: 0 ~ 2的32次方减 1=一共2的32次方个数;
有符号整数表示范围:-2的31次方 ~ 2的31次方减 1=也是一共2的32次方个数;java int整数有符号位的规则:
1 最高位是0的情况:此数必定是非负数,具体是多少,除最高位以外,其他的数按照二进制转换十进制规则
进行加即可,只要后面31位不全是0,就是正数,全是0就是整数0;
2 最高位是1的情况:此数必定是负数,后面31位取反再在最低为加二进制1。即是二进制的负数
在计算机内存中表示的方法:先将一个负数的符号位不看,把绝对值部分表示成二进制,然后把最高位31位
(031)置为1表示负数,剩下的31位中(030,最低为第0位) 先 -1 ,再把上下的低位31位(0~30)取反
就是负数在计算机中内存的表示方式!
负数的规则中:由于第31位是1为符号位,负数范围最大为-1,在那么最低位为1就行,先最低位减去1,再取反就是
11111111111111111111111111111111;print(-1);
打印结果:11111111111111111111111111111111,因为我们知道
这个数肯定是一个负数,所以先把最高位符号 1 拿出来先空着,030位取反:
【空的最高位符号位】0000000000000000000000000000000再加一就是
【空的最高位符号位】0000000000000000000000000000001,空的最高位符号位 没有因为进位发生替补,所以整个数就是
【空的最高位符号位】0000000000000000000000000000001,程序员直接翻译为-1
而要使得负数最小,反向验证:因为Integer.MIN_VALUE的结果是
10000000000000000000000000000000,因为我们知道这个数肯定是一个负数,所以先把最高位符号 1 拿出来~先空着
0~30位取反:【空的最高位符号位】1111111111111111111111111111111再加1,
最高位符号位的位置原来是空的,也由于进位变成了1,运算成了10000000000000000000000000000000(注意这时最高位的1不代表符号了)
因为我们程序员默认知道是负数了,运算规则也是如此,就是 -2的31次方
总结:知道是负数的情况下,取反加1时,最高位先不要了,或空着或先置为0都行!------->左神 取反操作加1的时候可以不要符号位,先空着或置为!!!
为什么负数这样算取反加一,首先 算数运算 + - * / 位运算 | & 等底层都是翻译成二进制运算。
因为要保证a + b中两个都是正数的相加和有一个数时负数的相加都是按照一套底层二进制逻辑进行位运算的。所以负数就是执行了
取反加1.其实宗旨就是为了运算时的执行速度很快!
负数的规则可以看看: print(-1);打印结果:11111111111111111111111111111111
*/
// print(-1);
// int a = Integer.MIN_VALUE;
// print(a);
// int b = 123823138;
// int c = b;取反符号是,二进制表示中,就是每一位由0变成了1或者由1变成了0
// print(b);
// print©;
// print(-5);
// System.out.println(Integer.MIN_VALUE);//-2147483648
// System.out.println(Integer.MAX_VALUE);//2147483647
/*
任何正数的相反数都有负数对应的负数,但是最小的负数的相反数没有正数对应!
* Integer.MIN_VALUE的绝对值比Integer.MAX_VALUE的绝对值大一,是因为
* 负数的最小值的绝对值可以到 2的31次方:由内存的二进制负数规则区分加一变成10000000000000000000000000000000
* 这里的最高位因为运算规则变成了1,此时的最高位1并不是代表负数的意思,是真正运算之后占位的1,有实际意义
* 正数的最大值的绝对值可以到 2的31次方-1:01111111111111111111111111111111,这里的最高位没有因为运算规则发生了变化
* */
// int a = 12319283;
// int b = 3819283;
// print(a);
// print(b);
// System.out.println(“=============”);
// print(a | b);
// print(a & b);
// print(a ^ b);//异或运算:相异为1;java语言中只有异或(^)没有同或符号
// 但是可以用代码实现 A 同或 B = (A ^ B)再按位取反
// public static int sameOr(int a, int b) {
// return ~(a ^ b);
// }
// int a = Integer.MIN_VALUE;
// print(a);//10000000000000000000000000000000
// print(a >> 1);//带符号右移,右移多少位,左侧的新位置-缺少的位由符号位来补!11000000000000000000000000000000
// print(a >>> 1);//不带符号右移 01000000000000000000000000000000,不带符号右移,其实也可以看作左侧的新位置-缺少的位由
// 0来补,非负数的带符号右移和不带符号右移是一样的效果!eg:1024;负数的带符号右移和不带符号右移不一样!
// 注意:CPU直接支持位运算,因此位运算比乘法运算效率高。与右移运算不同的是,左移运算没有有符号和无符号左移动,在左移时,移除
// 高位的同时在低位补0。与右移运算相同的是,当进行左移运算时,如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模,
// 例如对int类型的数移动33位,实际上只移动了33%32=1位。
int c = Integer.MIN_VALUE;
int d = -c ;//相反数 前面添加一个减号即可
System.out.println(c);//-2147483648 为什么负数的最小值的相反数还是本身,因为负数的绝对值比正数的绝对值大一,取相反之后无法表示。
System.out.println(d);//-2147483648
print(c);//10000000000000000000000000000000
print(d);//10000000000000000000000000000000
/*
* c的二进制表示:10000000000000000000000000000000 负数的另一种表示 ~N+1 = -N;
* 整体取反表示: 01111111111111111111111111111111
* 再加一表示: 10000000000000000000000000000000 负数最小值取反还是自己!
* 如果需要 Integer.MIN_VALUE这个取反操作得到的数,那么这个数其实该设计为long类型;
* */
/*
* 0的相反数,0:00000000000000000000000000000000
* 整体取反: 11111111111111111111111111111111
* 再加1: 1 00000000000000000000000000000000 由于进位最高位溢出了,不要了就是00000000000000000000000000000000=0
* */
// int a = 5;//000…101
// int b = -5;//整体取反111…010,在加1 就是111…011,把这个二进制0~30位取反加一就是100…101就是-5
// int b0 = (~a+1);//负数的另一种表示 ~N+1 = -N;
// System.out.println(a);//5
// System.out.println(b);//-5
// System.out.println(b0);//-5
// print(-5);//11111111111111111111111111111011 ((-5)+1):(-5)就是00000000000000000000000000000100,
// // 再加1就是00000000000000000000000000000101 = +5;
// int a = ~(-5) + 1;
// print(a);//通过上面的例子,~N + 1其中的N不管是正数负数都可以!这样足以说明为什么要把负数那样设计,
// 就是为了在底层进行各种运算的时候可以走一套逻辑,最底层的东西不要进行多种逻辑,否则系统异常庞大,一般运算都会很慢很慢。
//
// print©;
// print(d);
}
}