Java:常用类解析4(BigInteger类与BigDecimal类)

本文详细介绍了Java中的BigInteger类,用于表示任意大小整数,及其运算特点和转换规则。同时,对比了BigDecimal类,用于精确浮点数处理,包括精度保持和比较方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BigInteger类

基本定义

在Java中,由CPU原生提供的整型最大范围是64位 long 型整数。使用 long 型整数可以直接通过CPU指令进行计算,速度非常快。当我们使用的整数范围超过了 long 型,就只能用软件来模拟一个大整数。java.math.BigInteger 就是用来表示任意大小的整数, 其内部用一个 int[] 数组来模拟一个非常大的整数:

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

BigInteger 的运算示例

对 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

BigInteger 转换为基本类型

如上述代码所示,使用 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如下所示:

public class Main { 
	public static void main(String[] args) { 
		BigInteger n = new BigInteger("999999").pow(99);
		float f = n.floatValue(); 
		System.out.println(f); 
	} 
}

总结:

  • BigInteger 用于表示任意大小的整数;
  • BigInteger 是不变类,并且继承自 Number ;
  • 将 BigInteger 转换成基本类型时可使用 longValueExact() 等方法保证结果准确。

BigDecimal类

基本定义

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

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

基本方法

  1. 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
  1. 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
  1. 如果一个 BigDecimal 的 scale() 返回负数,表示这个数是个整数,并且末尾有2个0(参照上诉代码)。可以对一个 BigDecimal 设置它的 scale ,如果精度比原始值低,那么按照指定的方法进行四舍五入(RoundingMode.HALF_UP)或者直接截断( RoundingMode.DOWN):
public class Main { 
	public static void main(String[] args) { 
		BigDecimal d1 = new BigDecimal("123.456789"); 
		BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568 
		BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // 直接截断,123.4567 
		System.out.println(d2); 
		System.out.println(d3); 
	}
}

对 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,因为除不尽
  1. 对 BigDecimal 做除法的同时求余数,示例如下:
public class Main { 
	public static void main(String[] args) { 
		BigDecimal n = new BigDecimal("12.345"); 
		BigDecimal m = new BigDecimal("0.12"); 
		BigDecimal[] dr = n.divideAndRemainder(m); 
		System.out.println(dr[0]); //  102 
		System.out.println(dr[1]); // 0.875 
	} 
}

调用 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的整数倍 
}
  1. 在比较两个 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()!

BigInteger类与BigDecimal类的联系

如果查看 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() 。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值