JAVA - JAVA大数处理BigInteger与BigDecimal

时间:2023-02-11 11:02:26

背景知识

JAVA基本数据类型的取值范围

short的取值范围为-32768~32767,占2个字节

int的取值范围为-2147483648~2147483647,占4个字节

long的取值范围为-9223372036854774808~9223372036854774807,占8个字节

float的取值范围为3.402823e+38~1.401298e-454个字节 

double的取值范围为1.797693e+308~4.9000000e-3248个字节 

大数值BigInteger和BigDecimal

不管是整数型还是浮点型,它们的表示范围和精度都是有限的JAVA中有两个用于表示大数值的类BigInteger和BigDecimal,可以表示任意长度任意精度。当整数跟浮点数的取值范围或精度不能满足要求时,就需要用更大或者精度更高的类型BigInteger和BigDecimal了。

类加载:

import java.math.*;

BigInteger类实现了任意精度的整数运算除了基本的加减乘除操作之外,还提供了绝对值、相反数、最大公约数以及判断是否为质数等操作。

* 构造函数

public BigInteger(String val)

* 将普通的数值转换为大数值

public static BigInteger valueOf(long val)

* BigInteger类常用方法

public BigInteger add(BigInteger val):加法

public BigInteger subtract(BigInteger val):减法

public BigInteger multiply(BigInteger val):乘法

public BigInteger divide(BigInteger val):除法

public BigInteger remainder(BigInteger val):取余

public BigInteger mod(BigInteger m):取余

public BigInteger pow(int exponet):取参数的exponet次方操作

public BigInteger negate():取相反数

public BigInteger gcd(BigInteger val):取最大公约数

public BigInteger abs():取绝对值

public boolean equals(Object x):判断相等(仅限两个BigInteger对象之间比较)

public int compareTo(BigInteger val):比较大小(大于则返回正数,小于则返回负数,等于返回0

public BigInteger max(BigInteger val):返回较大值

//实例化一个大数字
        BigInteger num1 = new BigInteger("4"); 
        
        //将普通的数值转换为大数值
        BigInteger num2 = BigInteger.valueOf(3); 
        
        //取该大数字加2的操作
        System.out.println("加法操作:"+ num1.add(num2));
         
        //取该大数字减2的操作
        System.out.println("减法操作:"+ num1.subtract(num2));
         
        //取该大数字乘以2的操作
        System.out.println("乘法操作:"+ num1.multiply(num2));
         
        //取该大数字除以2的操作
        System.out.println("除法操作:"+ num1.divide(num2));
        
        //求余
        System.out.println("取余:"+ num1.remainder(num2));
        System.out.println("取余:"+ num1.mod(num2));
         
        //取该大数字的2次方
        System.out.println("做2次方操作:"+ num1.pow(2));    
         
        //取该大数字的相反数
        System.out.println("取相反数操作:"+ num1.negate());
        
        //取最大公约数
        System.out.println("取最大公约数:"+ num1.gcd(num2));
        
        //取绝对值
        System.out.println("取绝对值:"+ num1.abs());
        
        //判断相等
        System.out.println("判断相等:"+ num1.equals(num2));
        
        //比较大小
        System.out.println("比较大小:"+ num1.compareTo(num2));
        
        //取较大值
        System.out.println("取较大值:"+ num1.max(num2));

BigDecimal实现了任意精度的浮点数运算。BigDecimal类由任意精度的整数非标度值和32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以10的负scale次幂。因此,BigDecimal类表示的数值是(unscaledValue× 10-scale),可以处理任意长度的浮点数运算。

BigDecimal类的实现利用到了BigInteger类, 所不同的是BigDecimal类加入了小数位的概念,如BigDecimal d = new BigDecimal(new BigInteger(num),5),其中5表示的是5个小数位。BigDecimal类可以用来做超大的浮点数的运算,比如+-*/的运算,其中除法运算是最复杂的,因为商的位数还有除不断的情况下末位小数点的处理都是需要考虑的。

BigDecimal提供的算术运算返回的是精确的结果,这解决了 double 类型有时运算结果无法精确到一个值的问题

public static void main(String[] args) {
		// double型运算  2 - 1.1
		System.out.println("double 类型运算结果:" + (2 - 1.1));
		
		// BigDecimal运算   2 - 1.1
		BigDecimal bigD1 = BigDecimal.valueOf(2);
		BigDecimal bigD2 = BigDecimal.valueOf(1.1);
		System.out.println("BigDecaimal 运算结果:" + bigD1.subtract(bigD2).doubleValue());
}

运行结果

double 类型运算结果:0.8999999999999999
BigDecaimal 运算结果:0.9

* 构造函数

注意:由于基本数值类型不能准确地代表16位有效数以上的数字,在使用BigDecimal时,运用BigDecimal(String val)构造器创建对象才可避免丢失数字的精确度,才有意义。

public BigDecimal(int val)
public BigDecimal(double val)
public BigDecimal(long val)

public BigDecimal(String val)

* 将普通的数值转换为大数值

public static BigDecimal valueOf(double val)

public static BigDecimal valueOf(long val)

public static BigDecimal valueOf(long val, int scale):返回值为val/10scale

* 将大数值转换为字符串

public String toString()

* 将大数值转换为基本数据类型

public double doubleValue():将BigDecimal对象中的值以双精度数返回
public float floatValue():将BigDecimal对象中的值以单精度数返回
public long longValue():将BigDecimal对象中的值以长整数返回
public int intValue():将BigDecimal对象中的值以整数返回

注意:使用上述方法将BigDecimal对象以双精度数值返回时,将丢失数据的准确性使用时必须慎重。
* BigDecimal类常用方法

public BigDecimal add(BigDecimal val):加法

public BigDecimal subtract(BigDecimal val):减法

public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode):除法scale为精度取值, roundingMode为舍入方式

public BigDecimal negate():取相反数

public BigInteger abs():取绝对值

public boolean equals(Object x):判断相等(当且仅当两个BigDecimal对象数值和精度scale均相等时才返回true

public int compareTo(BigDecimal val):比较大小(仅比较两个BigDecimal对象数值是否相等,忽略精度;大于则返回正数,小于则返回负数,等于返回0

public BigDecimal max(BigDecimal val):返回较大值

* BigDecimal类的舍入

BigDecimal提供了一些舍入方案,通过 setScale方法返回舍入结果newScale表示保留小数位数,舍入方案默认采用四舍五入方式RoundingMode.HALF_UP。 

public BigDecimal setScale(int newScale)

public BigDecimal setScale(int newScale, RoundingMode roundingMode)

下面是 RoundingMode 各枚举项解释。

枚举项

解释

UP

舍入远离零的舍入模式。
在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。
此舍入模式始终不会减少计算值的大小。

DOWN

接近零的舍入模式。
在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截断)。
此舍入模式始终不会增加计算值的大小。

CEILING

接近正无穷大的舍入模式。
如果 BigDecimal 为正,则舍入行为与 UP 相同。
如果为负,则舍入行为与 DOWN 相同。
此舍入模式始终不会减少计算值。

FLOOR

接近负无穷大的舍入模式。
如果 BigDecimal 为正,则舍入行为与 DOWN 相同。
如果为负,则舍入行为与 UP 相同。
此舍入模式始终不会增加计算值。

HALF_UP

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入。
如果舍弃部分 >= 0.5,则舍入行为与 UP 相同;否则舍入行为与 ROUND_DOWN 相同。(四舍五入)。

HALF_DOWN

向”最接近的”数字舍入,如果与两个相邻数字的距离相等,则向下舍入。
如果舍弃部分 > 0.5,则舍入行为与 UP 相同;否则舍入行为与 DOWN 相同(五舍六入)。

HALF_EVEN

向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。
如果舍弃部分左边的数字为奇数,则舍入行为与 HALF_UP 相同;
如果为偶数,则舍入行为与 HALF_DOWN 相同。
在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。
此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。
如果前一位为奇数,则入位,否则舍去。
以下例子为保留小数点1位,那么这种舍入方式下的结果。
1.15>1.2
1.25>1.2

UNNECESSARY

用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。

如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

//实例化一个大数字
        BigDecimal num1 = new BigDecimal("4.10"); 
        
        //将普通的数值转换为大数值
        BigDecimal num2 = BigDecimal.valueOf(3.9);
        BigDecimal num3 = BigDecimal.valueOf(41, 1);
        
        //取该大数字加操作
        System.out.println("加法操作:"+ num1.add(num2));
         
        //取该大数字减操作
        System.out.println("减法操作:"+ num1.subtract(num2));
         
        //取该大数字乘操作
        System.out.println("乘法操作:"+ num1.multiply(num2));
         
        //取该大数字除操作
        System.out.println("除法操作:"+ num1.divide(num2, 4, RoundingMode.HALF_UP));
        
        //取该大数字的相反数
        System.out.println("取相反数操作:"+ num1.negate());
        
        //取绝对值
        System.out.println("取绝对值:"+ num1.abs());
        
        //判断相等, 当且仅当两个BigDecimal对象数值和精度scale均相等时才返回true
        System.out.println("判断相等:"+ num1.equals(BigDecimal.valueOf(41, 1)));
        System.out.println("判断相等:"+ num1.equals(BigDecimal.valueOf(410, 2)));
        
        //比较大小,仅比较两个BigDecimal对象数值是否相等,忽略精度
        System.out.println("比较大小:"+ num1.compareTo(BigDecimal.valueOf(41, 1)));
        System.out.println("比较大小:"+ num1.compareTo(BigDecimal.valueOf(410, 2)));
        
        //取较大值
        System.out.println("取较大值:"+ num1.max(num2));
        
        //舍入操作
        System.out.println("舍入操作:"+ num1.setScale(2, RoundingMode.HALF_UP));