最近看源码,复习了下基础运算知识,做下记录,一些表述与其他或者官方有些诧异,纯属个人心得,欢迎参考借鉴,指出错误,共勉。
public static void main(String[] args) {
//正数左移: 简单的理解为 移几位就在右边加几个0依次计算
System.out.println(3 << 1);//6 3乘以2的1次方 11 ==> 110 [4+2+0]
System.out.println(3 << 2);//12 3乘以2的2次方 11 ==> 1100 [8+4+0+0]
System.out.println(3 << 3);//24 3乘以2的3次方 11 ==> 11000 [16+8+0+0+0]
System.out.println(3 << 4);//48 3乘以2的4次方 11 ==> 110000 [32+16+0+0+0+0]
System.out.println(3 << 5);//96 3乘以2的5次方 11 ==> 1100000 [64+32+0+0+0+0+0]
//负数左移: 先获取补码,低位补0,高位超出舍弃,再取移位后的反码,再取补码[最终结果],以上操作符号位都不变
//原码 ==> 反码 ==> 补码 ==> 移位 ==> 再取反码 ==> 再取补码(最终结果)
System.out.println(-7 << 3); //-56
/*
原码 1000 0000 0000 0000 0000 0000 0000 0111
反码 1111 1111 1111 1111 1111 1111 1111 1000 [符号位不变,按位取反]
补码 1111 1111 1111 1111 1111 1111 1111 1001 [符号位不变,反码+1]
移位 1111 1111 1111 1111 1111 1111 1100 1000 [*符号位不变,高位超出位舍弃,低位补0]
再取反码 1000 0000 0000 0000 0000 0000 0011 0111 [符号位不变,按位取反]
再取补码 1000 0000 0000 0000 0000 0000 0011 1000 [符号位不变,反码+1]
*/
System.out.println(-297 << 5); //-9504
/*
原码 1000 0000 0000 0000 0000 0001 0010 1001
反码 1111 1111 1111 1111 1111 1110 1101 0110 [符号位不变,按位取反]
补码 1111 1111 1111 1111 1111 1110 1101 0111 [符号位不变,反码+1]
移位 1111 1111 1111 1111 1101 1010 1110 0000 [*符号位不变,高位超出位舍弃,低位补0]
再取反码 1000 0000 0000 0000 0010 0101 0001 1111 [符号位不变,按位取反]
再取补码 1000 0000 0000 0000 0010 0101 0010 0000 [符号位不变,反码+1]
*/
//正数右移(有符号右移): 简单的理解为 移几位 左边就删几位0依次计算
System.out.println(96 >> 1);//48 96除以2的1次方 1100000 ==> 0110000 [0+32+16+0+0+0+0]
System.out.println(96 >> 2);//24 96除以2的2次方 1100000 ==> 0011000 [0+0+16+8+0+0+0]
System.out.println(96 >> 3);//12 96除以2的3次方 1100000 ==> 0001100 [0+0+0+8+4+0+0]
System.out.println(96 >> 4);//6 96除以2的4次方 1100000 ==> 0000110 [0+0+0+0+4+2+0]
System.out.println(96 >> 5);//3 96除以2的5次方 1100000 ==> 0000011 [0+0+0+0+0+2+1]
//负数右移 : 获取反码 => 补码 => 移位[符号位不变,高位补1,低位超出位舍弃] => 再取移位后的反码 =>取移位后的补码
System.out.println(-56 >> 3); //-7
/*
原码 1000 0000 0000 0000 0000 0000 0011 1000
反码 1111 1111 1111 1111 1111 1111 1100 0111 [符号位不变,按位取反]
补码 1111 1111 1111 1111 1111 1111 1100 1000 [符号位不变,反码+1]
移位 1111 1111 1111 1111 1111 1111 1111 1001 [*符号位不变,高位补1,低位超出位舍弃]
再取反码 1000 0000 0000 0000 0000 0000 0000 0110 [符号位不变,按位取反]
再取补码 1000 0000 0000 0000 0000 0000 0000 0111 [符号位不变,反码+1](最终结果)
*/
System.out.println(-139 >> 5); //-5
/*
原码 1000 0000 0000 0000 0000 0000 1000 1011
反码 1111 1111 1111 1111 1111 1111 0111 0100 [符号位不变,按位取反]
补码 1111 1111 1111 1111 1111 1111 0111 0101 [符号位不变,反码+1]
移位 1111 1111 1111 1111 1111 1111 1111 1011 [*符号位不变,高位补1,低位超出位舍弃]
再取反码 1000 0000 0000 0000 0000 0000 0000 0100 [符号位不变,按位取反]
再取补码 1000 0000 0000 0000 0000 0000 0000 0101 [符号位不变,反码+1](最终结果)
*/
//正数无符号右移
//有符号右移:正数的符号位为0,移动时,符号位不动,高位补0
//无符号右移:高位补0,符号位跟随移动,符号位移动后也未0,
//其实和有符号位移所得结果是一样的,所以宏观上将,正数的有符号位移和无符号位移是没啥区别的
System.out.println(200 >> 5); //6
/*
原码 [0]000 0000 0000 0000 0000 0000 1100 1000
移位 [0]000 0000 0000 0000 0000 0000 0000 0110
*/
System.out.println(200 >>> 5); //6
/*
原码 [0]000 0000 0000 0000 0000 0000 1100 1000
移位 0000 0[0]00 0000 0000 0000 0000 0000 0110
*/
//负数无符号右移
System.out.println(-200 >>> 5); //134217721
/*
原码 1000 0000 0000 0000 0000 0000 1100 1000
反码 1111 1111 1111 1111 1111 1111 0011 0111 [符号位不变,按位取反]
补码 1111 1111 1111 1111 1111 1111 0011 1000 [符号位不变,反码+1]
移位 0000 0111 1111 1111 1111 1111 1111 1001 [*符号位也要偏移, 高位补符号位0, 低位超出位数舍弃](符号位变为0,为正数,三码合一,不用继续转换)(最终结果)
*/
System.out.println(-9 >>> 4); //268435455
/*
原码 1000 0000 0000 0000 0000 0000 0000 1001
反码 1111 1111 1111 1111 1111 1111 1111 0110 [符号位不变,按位取反]
补码 1111 1111 1111 1111 1111 1111 1111 0111 [符号位不变,反码+1]
移位 0000 1111 1111 1111 1111 1111 1111 1111 [*符号位也要偏移, 高位补符号位0, 低位超出位数舍弃](符号位变为0,为正数,三码合一,不用继续转换)(最终结果)
*/
//或运算 & 规则 :都为1时才为1
System.out.println(5 | 6); //值:7
/* 5: 101
6: 110
或值: 111 ==> [4+2+1] ==> 7
*/
System.out.println(520 | 20); //值:540
/* 520: 1000001000
20: 0000010100
或值: 1000011100 ==> [512+0+0+0+0+16+8+4+0+0] ==> 540
*/
//与运算 | 规则:有一个为1,则为1
System.out.println(5 & 6); //值:7
/* 5: 101
6: 110
与值: 100 ==> [4+0+0] ==> 4
*/
System.out.println(520 & 20); //值:0
/* 520: 1000001000
20: 0000010100
或值: 0000000000 ==> [0+0+0+0+0+0+0+0+0+0] ==> 0
*/
System.out.println(88 & 66); //值:0
/* 88: 1011000
66: 1000010
或值: 1000000 ==> [64+0+0+0+0+0+0] ==> 64
*/
//异或运算 ^ 规则:不同为1(左边补0不做计算)
System.out.println(5 ^ 6); //值:3
/* 5: 101
6: 110
异或值: 011 ==> [0+2+1] ==> 3
*/
System.out.println(520 ^ 20); //值:540
/* 520: 1000001000 => 0111110111
20: 0000010100 => 01011
异或值: 1000011100 ==> [512+0+0+0+0+16+8+4+0+0] ==> 540
*/
System.out.println(88 ^ 66); //值:0
/* 88: 1011000
66: 1000010
异或值: 0011010 ==> [0+0+16+8+0+2+0] ==> 26
*/
//取反运算 ~ 规则:按位取反
// 正数步骤 原码取反(值1) ==> 值1-1[符号位不变](值2) ==> 再取反[符号位不变](值3) ==> 转成10进制[注意符号位:1负数;0正数]
System.out.println(~7); // -8
/*
7: 0000 0000 0000 0000 0000 0000 0000 0111
取反:1111 1111 1111 1111 1111 1111 1111 1000 负数的补码
求反码:1111 1111 1111 1111 1111 1111 1111 0111 补码减1 ()
再取反得原码:1000 0000 0000 0000 0000 0000 0000 1000 得原码
符号位为1 确定值为负数;1000 转为10进制为8 ===> -8
*/
System.out.println(~9); //-10
/*
原码、反码、补码: 0000 0000 0000 0000 0000 0000 0001 0001
取反: 1111 1111 1111 1111 1111 1111 1110 1110
减一获得补码: 1111 1111 1111 1111 1111 1111 1110 1101
取反得原码: 1000 0000 0000 0000 0000 0000 0001 0010
*/
System.out.println(~88); //-89
/*
原码、反码、补码: 0000 0000 0000 0000 0000 0000 0101 1000
取反: 1111 1111 1111 1111 1111 1111 1010 0111
减一: 1111 1111 1111 1111 1111 1111 1010 0110
再取反: 1000 0000 0000 0000 0000 0000 0101 1001
*/
/**
* 负数二进制的三种表现形式
* 1.原码: 绝对值的二进制(符号位为1)
* 2.反码: 原码取反(符号位不参与运算)
* 3.补码: 取反之后 + 1
*/
// 负数步骤 转成原码(绝对值原码符号位为1) ==> 原码取反(值1) ==> 值1+1[符号位不变](值2) ==> 再取反[符号位不变](值3) ==> 转成10进制[注意符号位:1负数;0正数]
System.out.println(~-9); //8
/*
原码: 1000 0000 0000 0000 0000 0000 0000 1001
取反: 0111 1111 1111 1111 1111 1111 1111 0110
加一: 0111 1111 1111 1111 1111 1111 1111 0111
再取反: 0000 0000 0000 0000 0000 0000 0000 1000
*/
System.out.println(~-7); //6
/*
原码: 1000 0000 0000 0000 0000 0000 0000 0111
取反: 0111 1111 1111 1111 1111 1111 1111 1000
加一: 0111 1111 1111 1111 1111 1111 1111 1001
再取反: 0000 0000 0000 0000 0000 0000 0000 0110
*/
System.out.println(~-88); //87
/*
原码: 1000 0000 0000 0000 0000 0000 0101 1000
取反: 0111 1111 1111 1111 1111 1111 1010 0111
加一: 0111 1111 1111 1111 1111 1111 1010 1000
再取反: 0000 0000 0000 0000 0000 0000 0101 0111
*/
}