BigInteger和BigDecimal18

简介: BigInteger和BigDecimal18

BigInteger


在Java中,由CPU原生提供的整型最大范围是64位long型整数。使用long型整数可以直接通过CPU指令进行计算,速度非常快。


如果我们使用的整数范围超过了long型怎么办?这个时候,就只能用软件来模拟一个大整数。java.math.BigInteger就是用来表示任意大小的整数。BigInteger内部用一个int[]数组来模拟一个非常大的整数:


BigInteger bi = new BigInteger("1234567890");
System.out.println(bi.pow(5)); // 2867971860299718107233761438093672048294900000


对BigInteger做运算的时候,只能使用实例方法,例如,加法运算:


BigInteger i1 = new BigInteger("1234567890");
BigInteger i2 = new BigInteger("12345678901234567890");
BigInteger sum = i1.add(i2); // 12345678902469135780


和long型整数运算比,BigInteger不会有范围限制,但缺点是速度比较慢。


也可以把BigInteger转换成long型:


BigInteger i = new BigInteger("123456789000");
System.out.println(i.longValue()); // 123456789000
System.out.println(i.multiply(i).longValueExact()); // java.lang.ArithmeticException: BigInteger out of long range

使用longValueExact()方法时,如果超出了long型的范围,会抛出ArithmeticException。


BigInteger和Integer、Long一样,也是不可变类,并且也继承自Number类。因为Number定义了转换为基本类型的几个方法:

转换为byte:byteValue()

转换为short:shortValue()

转换为int:intValue()

转换为long:longValue()

转换为float:floatValue()

转换为double:doubleValue()


因此,通过上述方法,可以把BigInteger转换成基本类型。如果BigInteger表示的范围超过了基本类型的范围,转换时将丢失高位信息,即结果不一定是准确的。如果需要准确地转换成基本类型,可以使用intValueExact()、longValueExact()等方法,在转换时如果超出范围,将直接抛出ArithmeticException异常。


如果BigInteger的值甚至超过了float的最大范围(3.4x1038),那么返回的float是什么呢?


// BigInteger to float
import java.math.BigInteger;

Run


小结


BigInteger用于表示任意大小的整数;


BigInteger是不变类,并且继承自Number;


将BigInteger转换成基本类型时可使用longValueExact()等方法保证结果准确。


和BigInteger类似,BigDecimal可以表示一个任意大小且精度完全准确的浮点数。


BigDecimal bd = new BigDecimal("123.4567");
System.out.println(bd.multiply(bd)); // 15241.55677489


BigDecimal用scale()表示小数位数,例如:


BigDecimal d1 = new BigDecimal("123.45");
BigDecimal d2 = new BigDecimal("123.4500");
BigDecimal d3 = new BigDecimal("1234500");
System.out.println(d1.scale()); // 2,两位小数
System.out.println(d2.scale()); // 4
System.out.println(d3.scale()); // 0



通过BigDecimal的stripTrailingZeros()方法,可以将一个BigDecimal格式化为一个相等的,但去掉了末尾0的BigDecimal:


BigDecimal d1 = new BigDecimal("123.4500");
BigDecimal d2 = d1.stripTrailingZeros();
System.out.println(d1.scale()); // 4
System.out.println(d2.scale()); // 2,因为去掉了00

BigDecimal d3 = new BigDecimal("1234500");
BigDecimal d4 = d3.stripTrailingZeros();
System.out.println(d3.scale()); // 0
System.out.println(d4.scale()); // -2



如果一个BigDecimal的scale()返回负数,例如,-2,表示这个数是个整数,并且末尾有2个0。


可以对一个BigDecimal设置它的scale,如果精度比原始值低,那么按照指定的方法进行四舍五入或者直接截断:


import java.math.BigDecimal;
import java.math.RoundingMode;

Run


对BigDecimal做加、减、乘时,精度不会丢失,但是做除法时,存在无法除尽的情况,这时,就必须指定精度以及如何进行截断:


BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.456789");
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入
BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽

还可以对BigDecimal做除法的同时求余数:


import java.math.BigDecimal;

Run


调用divideAndRemainder()方法时,返回的数组包含两个BigDecimal,分别是商和余数,其中商总是整数,余数不会大于除数。我们可以利用这个方法判断两个BigDecimal是否是整数倍数:


BigDecimal n = new BigDecimal("12.75");
BigDecimal m = new BigDecimal("0.15");
BigDecimal[] dr = n.divideAndRemainder(m);
if (dr[1].signum() == 0) {
    // n是m的整数倍
}


比较BigDecimal


在比较两个BigDecimal的值是否相等时,要特别注意,使用equals()方法不但要求两个BigDecimal的值相等,还要求它们的scale()相等:


BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("123.45600");
System.out.println(d1.equals(d2)); // false,因为scale不同
System.out.println(d1.equals(d2.stripTrailingZeros())); // true,因为d2去除尾部0后scale变为2
System.out.println(d1.compareTo(d2)); // 0


必须使用compareTo()方法来比较,它根据两个值的大小分别返回负数、正数和0,分别表示小于、大于和等于。


总是使用compareTo()比较两个BigDecimal的值,不要使用equals()!


如果查看BigDecimal的源码,可以发现,实际上一个BigDecimal是通过一个BigInteger和一个scale来表示的,即BigInteger表示一个完整的整数,而scale表示小数位数:


public class BigDecimal extends Number implements Comparable<BigDecimal> {
    private final BigInteger intVal;
    private final int scale;
}

BigDecimal也是从Number继承的,也是不可变对象。


小结

BigDecimal用于表示精确的小数,常用于财务计算;


比较BigDecimal的值是否相等,必须使用compareTo()而不能使用equals()。


相关文章
|
7月前
|
存储 Java
你知道Java中的BigInteger类和BigDecimal类吗?
你知道Java中的BigInteger类和BigDecimal类吗?
110 0
|
7月前
|
存储 Java API
JavaSE&常用API(BigInteger,BigDecimal,Arrays,包装类)
JavaSE&常用API(BigInteger,BigDecimal,Arrays,包装类)
43 2
|
存储 Java API
从零开始学习 Java:简单易懂的入门指南之Objects、BigInteger、BigDecimal(十四)
从零开始学习 Java:简单易懂的入门指南之Objects、BigInteger、BigDecimal(十四)
|
Java
Java 中大数的处理方案BigInteger和BigDecimal类的使用
Java 中大数的处理方案BigInteger和BigDecimal类的使用
98 0
|
存储 Java
BigInteger与BigDecimal类
BigInteger与BigDecimal类
89 0
|
前端开发 Java
店铺业务场景分析、BigDecimal是Java提供的一个不变的、任意精度的有符号十进制数对象。它提供了四个构造器,有两个是用BigInteger构造、接口怎么使用的、重载与重写的区别?分别是什么?
店铺业务场景分析 一、协同店铺、竞争店铺极海数据返回给前端数据结构不一样 导入的数据结构 很有可能和自定义采集得到的数据结构不一样
187 1
店铺业务场景分析、BigDecimal是Java提供的一个不变的、任意精度的有符号十进制数对象。它提供了四个构造器,有两个是用BigInteger构造、接口怎么使用的、重载与重写的区别?分别是什么?
|
Java API
Java开发——18.常用类(包装类,拆箱和装箱;BigInteger+BigDecimal)
Java中只有两种数据类型:基本数据类型和引用数据类型。
Java开发——18.常用类(包装类,拆箱和装箱;BigInteger+BigDecimal)
|
存储 Java
Java常用类(5)--不可变的任意精度BigInteger、BigDecimal类
Java常用类(5)--不可变的任意精度BigInteger、BigDecimal类
192 0
Java常用类(5)--不可变的任意精度BigInteger、BigDecimal类
|
Java 索引
java中大数的计算BigInteger和BigDecimal两个类的常用方法
java中大数的计算BigInteger和BigDecimal两个类的常用方法
108 0
Java学习路线-18:数字操作类Math、Random、BigInteger、BigDecimal
Java学习路线-18:数字操作类Math、Random、BigInteger、BigDecimal
155 0