JAVA中的BigInteger和BigDecimal

目录

背景:

BigInteger:

获取对象的方式有四种:

常用成员方法:

BigInteger 底层存储方式:

BigDecimal:

获取对象的方法

常用成员方法:

方法 5 中的舍入模式:

BigDecimal 的底层存储方式:


背景:

BigInteger和BigDecimal类在Java中的存在意义主要在于解决以下问题:

  • 大整数运算:

BigInteger 类能够处理任意大小的整数,不受 Java 中基本类型(如 int、long)的最大值限制。这对于需要进行大整数计算的场景非常有用,比如在密码学、大素数分解、大数因子分解等算法中。

  • 高精度浮点数运算:

BigDecimal 类则用于精确的小数或浮点数计算,尤其在金融、科学计算等领域特别重要。由于 Java 的基本类型 double 和 float,存在一定的精度限制且不支持完全精确的十进制表示。而 BigDecimal 可以提供任意精度的小数运算,确保结果准确无误,避免了因浮点数舍入误差带来的问题。

  • 数值稳定性:

使用 BigDecimal 可以保证在涉及货币计算、比例计算或者要求绝对精确的情况下不会出现舍入误差,这在商业应用中至关重要。

  • 数学运算完整性:

这两个类提供了丰富的算术运算方法,包括加减乘除、模运算、开方、指数、取余数等等,使开发者能方便地对大整数和高精度小数执行各种复杂的数学运算。

综上所述,BigInteger 和 BigDecimal 在无法满足基本数据类型范围和精度需求时,为程序提供了更强大的数值处理能力,确保了数值计算的准确性和完整性。


BigInteger:

获取对象的方式有四种:


3 种构造方法:

4 为静态方式获取对象:


构造方法 123 示例:

public class Test01 {
    public static void main(String[] args) {
//1.[0,2^2-1],注意都是闭区间
    BigInteger bd1=new BigInteger(2,new Random());
       
//2.当不知道数字多大时使用(可大于long),字符串中必须是整数
    BigInteger bd2=new BigInteger("99999999999999999999999999999999");

//3.    //细节:
        //1将指定进制的数换成十进制
        //2字符串中必须是整数
        //3且不超出进制范围
    BigInteger bd3 = new BigInteger("1110", 8);
    System.out.println(bd3);//584

方法 4 示例:

//4.静态方法获取Big Integer的对象。

//表示范围为long
BigInteger bd4 = BigInteger.valueOf(9223372036854775807L);
//(超出Int返回添加L表示long)
----------------------------------

//内部有优化:
//-16-16做了优化,提前创建好了对象,若多次获取不会创建新的,目的是节约内存
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,前后地址不一样


//System.out.println(Long.MIN_VALUE);//-9223372036854775808
//System.out.println(Long.MAX_VALUE);//9223372036854775807

valueOf 源码:


构造方法 2、4 最常用,

2 接收的是字符串,4 接收的是 long 类型


总结:


常用成员方法:


注意点:在进行 BigInteger 的运算时,不是直接使用对象来运算,而是用对象来调用方法来进行运算。


BigInteger 方法使用示例:

BigInteger bd1= BigInteger.valueOf(10);
BigInteger bd2= BigInteger.valueOf(3);
//1.add
BigInteger bd3 = bd1.add(bd2);
System.out.println(bd3);//13
//2.subtract
BigInteger subtract = bd1.subtract(bd2);
System.out.println(subtract);//7
//3.multiply
BigInteger multiply = bd1.multiply(bd2);
System.out.println(multiply);//30
//4.divide
BigInteger divide = bd1.divide(bd2);
System.out.println(divide);//3(整数相除小数不保留)

//5.[]divide And Remainder--用数组存储
BigInteger[] b = bd1.divideAndRemainder(bd2);
System.out.println(b[0]);//3-商
System.out.println(b[1]);//1-余数

//6.equals在BigInteger中已经重写(比较数值)
BigInteger bd5= BigInteger.valueOf(10);
BigInteger bd6= BigInteger.valueOf(10);
boolean results = bd5.equals(bd6);
System.out.println(results);//true

//7.pow--括号内只能填int
BigInteger pow = bd1.pow(2);
System.out.println(pow);//100--bd1的2次幂

//8.maxmin
BigInteger max = bd1.max(bd2);
System.out.println(max);//10
//*注意*
System.out.println(max==bd1);//true

//9.intValue,longvalue....
//要遵守类型范围
BigInteger a = BigInteger.valueOf(99);
long i = a.longValue();//  <--
System.out.println(i);

BigInteger 底层存储方式:

BIgInteger 为什么能存很大的数据?

其实在底层是用一个 int 类型的数组来存储,首先将这个很大的数据分成几段,从然后存入数组的不同位置。


我们用 dbug 模式验证一下,

1.

2.

3.

4.

当signum为-1时,表示该数为负;当signum为0时,表示该数为0;当signum为1时,表示该数为正数。


BigDecimal:

前言:

System.out.println(0.09+0.01);
System.out.println(0.216-0.1);
System.out.println(0.226*0.01);
System.out.println(0.09/0.1);

控制台:

0.09999999999999999

0.11599999999999999

0.0022600000000000003

0.8999999999999999

直接的运算出现了精度丢失的情况:

这是为什么?

因为计算机是使用二进制来运算的,在我们输入十进制小数后得到的二进制数有可能很长(因为进制转换乘 R 取整)如下面几个小数:

,而 对于 double 类型来说,小数部份的位数是有限的(52 位)

那么这时 0.226 就要有 3 位 不得不被舍弃了,所以造成了数据的不准确


实际开发中涉及金融,证券等对数字精度要求高的场景,为解决精度丢失问题,就有了BigDecimal。


获取对象的方法

2 种构造:

3 为静态方式获取

构造方法示例:

//1.通过传递double小数来创建对象
//仍然有可能不精确·,所以不建议使用
BigDecimal bd1=new BigDecimal(0.01);
BigDecimal bd2=new BigDecimal(0.09);
System.out.println(bd1);
System.out.println(bd2);
//0.01000000000000000020816681711721685132943093776702880859375
//0.0899999999999999966693309261245303787291049957275390625

//2通过传递字符串表示的小数来创建对象(当较大的小数)
//建议使用·
BigDecimal bd3=new BigDecimal("0.01");
BigDecimal bd4=new BigDecimal("0.09");
System.out.println(bd3);
System.out.println(bd4);
//        0.01
//        0.09
System.out.println(bd3.add(bd4));//0.10

静态获取对象

//3.通过静态方法获取对象(当较小的小数)
BigDecimal bd6 = BigDecimal.valueOf(10);//传递整数也可以
System.out.println(bd6);//10

//和BigInteger一样内部有优化
//如果我们创建的是0-10之间的整数(包含0,10)
//那么会返回已经创建好的对象,不会再new
BigDecimal bd7=BigDecimal.valueOf(10);
BigDecimal bd8=BigDecimal.valueOf(10);
System.out.println(bd7==bd8);//true

// (6.0之类的是小数)
BigDecimal bd7=BigDecimal.valueOf(6.0);
BigDecimal bd8=BigDecimal.valueOf(6.0);
System.out.println(bd7==bd8);//false

//若要表示的数较小,不超过double取值范围,用静态方法创建对象

//要表示的数较大,超过double取值范围,用构造方法创建对象


常用成员方法:

BigDecimal bd1=BigDecimal.valueOf(10.0);
BigDecimal bd2=BigDecimal.valueOf(3.0);

//1.add
BigDecimal bd3 = bd1.add(bd2);
System.out.println(bd3);//13.0

//2.subtract
BigDecimal bd4 = bd1.subtract(bd2);
System.out.println(bd4);//7.0

//3.cheng

BigDecimal bd5=bd1.multiply(bd2);
System.out.println(bd5);//30.0

//4.chu

BigDecimal divide = bd1.divide(bd2);//除不尽则使用下面方法
System.out.println(divide);

//余五位小数,并四舍五入
BigDecimal bd6 = bd1.divide(bd2, 5, RoundingMode.HALF_UP);
System.out.println(bd6);//3.33333



方法 5 中的舍入模式:

RoundingMode:

四舍五入最常用....


BigDecimal 的底层存储方式:

底层存储也是一个数组

biglnteger 采取分段存储,BigDecimal 采取的是遍历存储,

在 jdk 低版本下将遍历到的字符存入字符数组 Char[]

并用其对应得 Ascii 码值来记录

高版本 jdk 是用 byte 数组直接记录字符的 Ascii 码值