一、常见的位运算使用场景
1.&(按位与):两个都为1,结果为1。
//&运算:相同为1,不同为0
int n1 = 2;//2的二进制数为:10
int n2 = 3;//3的二进制数为:11
int ret = n1&n2;//相与的结果为:10(二进制),转换为十进制为:2
System.out.println(ret);//所以结果为:2(十进制)
2.|(按位或):只要有一个为1,则结果为1。
//|运算:有1为1,无1为0
int n1 = 2;//2的二进制数为:10
int n2 = 3;//3的二进制数为:11
int ret = n1|n2;//相或的结果为:11(二进制),转换为二进制为:3
System.out.println(ret);//所以结果为:3(十进制)
3.~(按位取反):0变为1,1变为0。
int n3 = 2;//2的二进制数为:0000 0010(原码)
n3 = ~n3; //取反后:1111 1101(补码)
System.out.println(n3);//输出为十进制,也就是要将补码转换为原码
//(1)如果补码的符号位为“0”,表示是一个正数,所以补码就是该数的原码。
//(2)如果补码的符号位为“1”,表示是一个负数,求原码的操作可以是:符号位为1,各位取反,然后再整个数加1。
//所以:
// n3的符号位为1,各位取反+1为:1000 0010 + 1 = 1000 0011;
//所以1000 0011(二进制)再转换为十进制为:(最高位是符号位)-3;
4.^(按位异或):两边不同就为1。
//^运算:不同为1,相同为0
int n1 = 2;//2的二进制数为:10
int n2 = 3;//3的二进制数为:11
int ret = n1^n2;//异或的结果为:01(二进制),转换为二进制为:1
System.out.println(ret);//所以结果为:1(十进制)
5.<<(左移):各二进制位全部左移n位,左移翻倍。
//<<运算:各二进制位全部左移n位。左移翻倍
int n1 = 2;//2的二进制数为:0010
int n2 = 3;//3的二进制数为:0011
int ret1 = n1<<2;//n1的二进制数(0010)向左移动2位:1000
int ret2 = n2<<1;//n1的二进制数(0011)向左移动1位:0110
System.out.println(ret1);//所以ret1结果为:8(十进制)
System.out.println(ret2);//所以ret2结果为:6(十进制)
6.>>(右移):各二进制位全部右移n位,右移减半。
//>>运算:各二进制位全部右移n位。右移减半
int n1 = 8;//2的二进制数为:1000
int n2 = 6;//3的二进制数为:0110
int ret1 = n1>>2;//n1的二进制数(1000)向左移动2位:0010
int ret2 = n2>>1;//n1的二进制数(0110)向左移动1位:0011
System.out.println(ret1);//所以ret1结果为:2(十进制)
System.out.println(ret2);//所以ret2结果为:3(十进制)
注意:
- 只要涉及到‘位’,就涉及到二进制。
- 整数之间可以进行位运算,浮点数之间不可以进行位运算。
二、整数类型运算时的类型溢出问题,产生原因以及解决办法。
产生原因:
基本数据类型都有自己的范围大小,在进行运算时,有时会超出整数类型表示的范围,导致溢出错误。
整形基本数据类型的范围:
byte:-128~+127
short:-32768~+32767
int:-2147483648~+2147483647(-2^31~+2^31-1)
long:-2^63~+2^63-1
解决办法:
1.当byte进行运算溢出时:可将结果的范围改为short、int、long等比byte范围大的类型。
byte b1 = 127;
byte b2 = 1;
byte ret1 = (byte) (b1+b2);
System.out.println("ret1="+ret1);
结果为:ret1=-128
- 类型变为short后:
byte b1 = 127;
byte b2 = 1;
short ret1 = (short) (b1+b2);
System.out.println("ret1="+ret1);
结果为: ret1=128
- 类型变为int后:
byte b1 = 127;
byte b2 = 1;
int ret1 = b1+b2;
System.out.println("ret1="+ret1);
结果为:ret1=128
- 类型变为long后:
byte b1 = 127;
byte b2 = 1;
long ret1 = b1+b2;
System.out.println("ret1="+ret1);
结果为:ret1=128
以此类推,当short、int类型运算溢出时,都可以用比他们范围大的类型来表示结果类型。
2.当long类型运算溢出时:就要使用BigInteger来保存超大整数了,如下:
3.使用BigInteger保存超大整数:BigInteger支持大量的整数运算,包括加减乘除等等,它会将两个BigInteger对象的数组逐位进行运算,并将结果保存在新的BigInteger对象中,这种运算机制保证了BigInteger的运算精度和准确性。
public static void main(String[] args) {
//使用BigInteger保存“超大整数”
BigInteger n1 = new BigInteger("2123456789098765678978");
BigInteger n2 = new BigInteger("9876543234567890678908");
//通过调用方法,进行加减乘除运算
//加法
BigInteger sum = n1.add(n2);
System.out.println(sum);
//减法
BigInteger sub = n2.subtract(n1);
System.out.println(sub);
//乘法
BigInteger mul = n1.multiply(n2);
System.out.println(mul);
//除法
BigInteger div = n2.divide(n1);
System.out.println(div);
//混合运算
BigInteger n3 = new BigInteger("10");
BigInteger ret = n3.multiply(n1).add(n2);
System.out.println(ret);
}
结果为:
12000000023666656357886
7753086445469124999930
20972412784270670442054681749751626003596024
4
31111111125555547468688
三、浮点类型运算时的精度丢失问题,产生原因以及解决办法。
产生原因:
因为计算机内部通过二进制的形式来保存浮点数,无法精确的表示十进制的小数,所以会产生经度丢失的问题。具体情况如下:
十进制的小数再进行二进制转换时,整数部分会除二取余,小数部分会乘二取整,在乘二取整的过程中,会产生无限循环的情况,所以就出现了精度丢失。
解决办法:
在进行大型金融等计算时,应该用BigDecimal类型,使用它的加减乘除方法俩进行计算。
BigDecimal n1 = new BigDecimal("10.3");
BigDecimal n2 = new BigDecimal("3.0");
//加法
BigDecimal sum = n1.add(n2);
System.out.println(sum); //输出为:13.3
//减法
BigDecimal sub = n1.subtract(n2);
System.out.println(sub); //输出为:7.3
//乘法
BigDecimal mul = n1.multiply(n2);
System.out.println(mul); //输出为:30.90
//浮点数的除法运算容易产生无限循环:
//可以用下图所示的三个参数的方法:
//参数一:被除数
//参数二:保留几位小数
//参数三:小数位数的截取方式
//RoundingMode.HALF_DOWN:代表四舍五入
BigDecimal div = n1.divide(n2, 3,RoundingMode.HALF_DOWN);
System.out.println(div);//输出为:3.433
在浮点数进行除法运算时,调用如下方法: