目录
BigInteger类
平时在存储整数的时候,Java中默认是int类型,int类型有取值范围:-2147483648 ~ 2147483647。如果数字过大,可以使用long类型,但是如果long类型也表示不下怎么办呢?
就需要用到BigInteger,可以理解为:大的整数。理论上最大到42亿的21亿次方
基本上在内存撑爆之前,都无法达到这个上限。
查看API文档,可以看到API文档中关于BigInteger类的定义如下:
BigInteger所在包是在java.math包下,因此在使用的时候就需要进行导包。可以使用BigInteger类进行大整数的计算
常见方法
构造方法
public BigInteger(int num, Random rnd)
//获取随机大整数,范围:[0 ~ 2的num次方 -1]
public BigInteger(String val)
//获取指定的大整数
public BigInteger(String val, int radix)
//获取指定进制的大整数
下面这个不是构造,而是一个静态方法获取BigInteger对象
public static BigInteger valueOf(long val)
//静态方法获取BigInteger的对象,内部有优化
示例:
public static void main(String[] args) {
//对象一旦创建里面的数据不能发生改变
//1.获取一个随机的大整数
Random r=new Random();
BigInteger bd1 = new BigInteger(4,r);//[0 ~ 15]
//2.获取一个指定的大整数,可以超出long的取值范围
//细节:字符串中必须是整数,否则会报错
//BigInteger bd2 = new BigInteger("1.1");//报错
//BigInteger bd3 = new BigInteger("abc");//报错
//3.获取指定进制的大整数
//细节:
//1.字符串中的数字必须是整数
//2.字符串中的数字必须要跟进制吻合。
//比如二进制中,那么只能写0和1,写其他的就报错。
//BigInteger bd4 = new BigInteger("123", 2);//报错
//转为十进制
BigInteger bd4 = new BigInteger("100", 2);
System.out.println(bd4);//4
//4.静态方法获取BigInteger的对象,内部有优化
//细节:
//1.能表示范围比较小,只能在long的取值范围之内,如果超出long的范围就不行了。
//2.在内部对常用的数字: -16 ~ 16 进行了优化。
// 提前把-16~16 先创建好BigInteger的对象,如果多次获取不会重新创建新的。
BigInteger bd5 = BigInteger.valueOf(16);
BigInteger bd6 = BigInteger.valueOf(16);
System.out.println(bd5 == bd6);//true
BigInteger bd7 = BigInteger.valueOf(17);
BigInteger bd8 = BigInteger.valueOf(17);
System.out.println(bd7 == bd8);//false
//5.对象一旦创建内部的数据不能发生改变
BigInteger bd9 =BigInteger.valueOf(1);
BigInteger bd10 =BigInteger.valueOf(2);
//此时,不会修改参与计算的BigInteger对象中的值
//而是产生了一个新的BigInteger对象记录
BigInteger result=bd9.add(bd10);
System.out.println(result);//3
}
构造方法小结:
-
如果BigInteger表示的数字没有超出long的范围,可以用静态方法获取。
-
如果BigInteger表示的超出long的范围,可以用构造方法获取。
-
对象一旦创建,BigInteger内部记录的值不能发生改变。
-
只要进行计算都会产生一个新的BigInteger对象
常见成员方法
BigDecimal类中使用最多的还是提供的进行四则运算的方法,如下:
public BigInteger add(BigInteger val)
//加法
public BigInteger subtract(BigInteger val)
//减法
public BigInteger multiply(BigInteger val)
//乘法
public BigInteger divide(BigInteger val)
//除法,获取商
public BigInteger[] divideAndRemainder(BigInteger val)
//除法,获取商和余数
public boolean equals(Object x)
//比较是否相同,已重写,比较变量值
public BigInteger pow(int exponent)
//次幂、次方
public BigInteger max/min(BigInteger val)
//返回较大值/较小值
public int intValue(BigInteger val)
//转为int类型整数,超出范围数据有误
代码实现:
public static void main(String[] args) {
//1.创建两个BigInteger对象
BigInteger bd1 = BigInteger.valueOf(10);
BigInteger bd2 = BigInteger.valueOf(5);
//2.加法
BigInteger bd3 = bd1.add(bd2);
System.out.println(bd3);//15
//3.除法,获取商和余数
BigInteger[] arr = bd1.divideAndRemainder(bd2);
System.out.println(arr[0]);//2 商
System.out.println(arr[1]);//0 余
//4.比较是否相同
boolean result = bd1.equals(bd2);
System.out.println(result);//false
//5.次幂
BigInteger bd4 = bd1.pow(2);
System.out.println(bd4);//100
//6.max
BigInteger bd5 = bd1.max(bd2);//10
//返回值大的那个对象,不会创建新的对象
//7.转为int类型整数,超出范围数据有误
BigInteger bd6 = BigInteger.valueOf(2147483647L);//最大值,不能大于这个数
int i = bd6.intValue();
System.out.println(i);
BigInteger bd6 = BigInteger.valueOf(200);
double v = bd6.doubleValue();
System.out.println(v);//200.0
}
底层存储方式
对于计算机而言,其实是没有数据类型的概念的,都是0101010101,数据类型是编程语言自己规定的,所以在实际存储的时候,先把具体的数字变成二进制的补码,从低位到高位,每32个bit为一组,把每组数据转为十进制,存储在数组中。(了解就行)
数组中最多能存储元素个数:21亿多
数组中每一位能表示的数字:42亿多
理论上,BigInteger能表示的最大数字为:42亿的21亿次方。
但是还没到这个数字,电脑的内存就会撑爆,所以一般认为BigInteger是无限的
存储方式如图所示:
BigDecimal类
看到如下程序:
public class BigDecimalDemo01 {
public static void main(String[] args) {
System.out.println(0.09 + 0.01);//0.09999999999999999
}
}
结果其实是一个丢失精度的结果。为什么会产生精度丢失呢?
在使用float或者double类型的数据在进行数学运算的时候,很有可能会产生精度丢失问题。计算机底层在进行运算的时候,使用的都是二进制数据。当在程序中写了一个十进制数据 ,在进行运算的时候,计算机会将这个十进制数据转换成二进制数据,然后再进行运算,计算完毕以后计算机会把运算的结果再转换成十进制数据用来展示;
如果我们使用的是整数类型的数据进行计算,那么在把十进制数据转换成二进制数据的时候不会存在精度问题;
如果我们的数据是浮点类型的数据,有的时候计算机并不会将这个数据完全转换成一个二进制数据,而是将这个将其转换成一个无限的趋近于这个十进数的二进制数据; 这样使用一个不太准确的数据进行运算的时候, 最终就会造成精度丢失;为了提高精度,Java就提供BigDecimal供我们进行数据运算。
查看API文档,可以看到API文档中关于BigDecimal类的定义如下:
BigDecimal所在包是在java.math包下,因此在使用的时候就需要进行导包。可以使用BigDecimal类进行更加精准的数据计算。
作用
- 用于小数的精确计算
- 用来表示很大的小数
常见方法
构造方法
最常用的构造方法:
//1.通过传递double类型的小数来创建对象
//细节:
//这种方式有可能是不精确的,所以不建议使用
//BigDecimal bd1 = new BigDecimal(0.01);
//BigDecimal bd2 = new BigDecimal(0.09);
// system.out.println(bd1);
// system.out.println(bd2);
//2.通过传递字符串表示的小数来创建对象
BigDecimal bd3 = new BigDecimal( val: "0.01");
BigDecimal bd4 = new BigDecimal( val: "0.09");
BigDecimal bd5 = bd3.add(bd4);
System.out.println(bd3);//0.01
System.out.print1n(bd4);//0.09
System.out.println(bd5);//0.10
//3.通过静态方法获取对象
BigDecimal bd6 = BigDecimal.value0f(10);
system.out.print1n(bd6);//10
//细节:
//1.如果要表示的数字不大,没有超出double的取值范围,建议使用静态方法
//2.如果要表示的数字比较大,超出了double的取值范围,建议使用构造方法
//3.如果传递的是0~10之间的整数,包含0,包含10,那么方法会返回已经创建好的对象,不会重新new
常见成员方法
BigDecimal类中使用最多的还是提供的进行四则运算的方法,如下:
public BigDecimal add(BigDecimal value) // 加法运算
public BigDecimal subtract(BigDecimal value) // 减法运算
public BigDecimal multiply(BigDecimal value) // 乘法运算
public BigDecimal divide(BigDecimal value) // 触发运算
案例1:基本的四则运算
public class BigDecimalDemo01 {
public static void main(String[] args) {
// 创建两个BigDecimal对象
BigDecimal b1 = new BigDecimal("0.3") ;
BigDecimal b2 = new BigDecimal("4") ;
// 调用方法进行b1和b2的四则运算,并将其运算结果在控制台进行输出
System.out.println(b1.add(b2)); //4.3
System.out.println(b1.subtract(b2)); //-3.7
System.out.println(b1.multiply(b2)); //1.2
System.out.println(b1.divide(b2)); //0.075
}
}
使用BigDecimal类来完成浮点数的计算不会存在损失精度的问题
案例2:除法的特殊情况
如果使用BigDecimal类型的数据进行除法运算的时候,得到的结果是一个无限循环小数,那么就会报错:ArithmeticException。 如下代码所示:
public class BigDecimalDemo02 {
public static void main(String[] args) {
// 创建两个BigDecimal对象
BigDecimal b1 = new BigDecimal("1") ;
BigDecimal b2 = new BigDecimal("3") ;
// 调用方法进行b1和b2的除法运算,并且将计算结果在控制台进行输出
System.out.println(b1.divide(b2));
}
}
运行程序进行测试,控制台输出结果如下所示:
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.base/java.math.BigDecimal.divide(BigDecimal.java:1716)
at com.itheima.api.bigdecimal.demo02.BigDecimalDemo02.main(BigDecimalDemo02.java:14)
针对这个问题怎么解决,此时就需要使用到BigDecimal类中另外一个divide方法,如下所示:
BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
上述divide方法参数说明:
divisor: 除数对应的BigDecimal对象;
scale: 精确的位数;
roundingMode: 取舍模式;
取舍模式被封装到了RoundingMode这个枚举类中,在这个枚举类中定义了很多种取舍方式。
最常见的取舍方式有如下几个:
UP() , FLOOR(直接删除) , HALF_UP(4舍五入)
可以通过如下格式直接访问这些取舍模式:枚举类名.变量名
如下所示:
public class BigDecimalDemo02 {
public static void main(String[] args) {
// 调用方法
method_03() ;
}
// 演示取舍模式HALF_UP
public static void method_03() {
// 创建两个BigDecimal对象
BigDecimal b1 = new BigDecimal("0.3") ;
BigDecimal b2 = new BigDecimal("4") ;
// 调用方法进行b1和b2的除法运算,并且将计算结果在控制台进行输出
System.out.println(b1.divide(b2 , 2 , RoundingMode.HALF_UP));
}
// 演示取舍模式FLOOR
public static void method_02() {
// 创建两个BigDecimal对象
BigDecimal b1 = new BigDecimal("1") ;
BigDecimal b2 = new BigDecimal("3") ;
// 调用方法进行b1和b2的除法运算,并且将计算结果在控制台进行输出
System.out.println(b1.divide(b2 , 2 , RoundingMode.FLOOR));
}
// 演示取舍模式UP
public static void method_01() {
// 创建两个BigDecimal对象
BigDecimal b1 = new BigDecimal("1") ;
BigDecimal b2 = new BigDecimal("3") ;
// 调用方法进行b1和b2的除法运算,并且将计算结果在控制台进行输出
System.out.println(b1.divide(b2 , 2 , RoundingMode.UP));
}
}
后期在进行两个数的除法运算的时候,常常使用的是可以设置取舍模式的divide方法
底层存储方式
把数据看成字符串,遍历得到里面的每一个字符,把这些字符在ASCII码表上的值,都存储到数组中。