BigDecimal详解及注意事项

本文详细介绍BigDecimal的使用方法,包括创建对象、加减乘除运算、大小比较及等值比较等核心功能。同时提供了如何避免精度损失的最佳实践。

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

BigDecimal简介

  1. 浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能用 equals 来判断。
  2. BigDecimal 可以实现对浮点数的运算,不会造成精度丢失;
  3. 通常情况下,大部分需要浮点数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 BigDecimal 来做的;

BigDecimal常用方法

创建BigDecimal

  1. 禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象,因为其存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
  2. 在使用 BigDecimal 时,为了防止精度丢失,推荐使用BigDecimal(String val)构造方法或者 BigDecimal.valueOf(double val) 静态方法来创建对象;

如:BigDecimal g = new BigDecimal(0.1),实际存储为0.1000000000000000055511151231257827021181583404541015625
推荐入参为String的构造方法,或BigDecimal的valueOf方法,此方法内部其实执行了Double的toString,而Double的toString按double实际能表达的精度对尾数进行了截断。
BigDecimal b1 = new BigDecimal(“0.1”);
BigDecimal b2 = BigDecimal.valueOf(0.1);

加减乘除

  • add方法用于将两个BigDecimal对象相加;
  • subtract方法用于将两个BigDecimal对象相减;
  • multiply方法用于将两个BigDecimal对象相乘;
  • divide方法用于将两个BigDecimal对象相除;

使用 divide 方法的时候尽量使用 3 个参数版本,并且RoundingMode 不要选择 ROUND_UNNECESSARY,否则很可能会遇到 ArithmeticException(无法除尽出现无限循环小数的时候),其中 scale 表示要保留几位小数,roundingMode 代表保留规则。

public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode);

RoundingMode枚举:

  1. UP:向远离零的方向舍入。若舍入位为非零,则对舍入部分的前一位数字加1;若舍入位为零,则直接舍弃;
  2. DOWN:向接近零的方向舍入。不论舍入位是否为零,都直接舍弃;
  3. CEILING:向正无穷大的方向舍入。若 BigDecimal 为正,则舍入行为与 ROUND_UP 相同;若为负,则舍入行为与 ROUND_DOWN 相同。即为向上取整模式;
  4. FLOOR:向负无穷大的方向舍入。若 BigDecimal 为正,则舍入行为与 ROUND_DOWN 相同;若为负,则舍入行为与 ROUND_UP 相同。即为向下取整模式。
  5. HALF_UP:四舍五入。若舍入位大于等于5,则对舍入部分的前一位数字加1;若舍入位小于5,则直接舍弃。
  6. HALF_DOWN:五舍六入。若舍入位大于5,则对舍入部分的前一位数字加1;若舍入位小于等于5,则直接舍弃。
  7. HALF_EVEN:银行家舍入模式。若(舍入位大于5)或者(舍入位等于5且前一位为奇数),则对舍入部分的前一位数字加1;若(舍入位小于5)或者(舍入位等于5且前一位为偶数),则直接舍弃;
  8. UNNECESSARY:不舍位, 精度位数小于小数位数会抛出ArithmeticException;

大小比较

a.compareTo(b) : 返回 -1 表示 a 小于 b,0 表示 a 等于 b , 1 表示 a 大于 b。

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("0.9");
System.out.println(a.compareTo(b));// 1

BigDecimal等值比较问题

BigDecimal的等值比较应使用compareTo(),而不是equals(),因为equals()会比较值和精度(1.0与1.00返回结果为false),而compareTo()会忽略精度。

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("1.0");
System.out.println(a.equals(b));//false
System.out.println(a.compareTo(b));//0

保留小数位数

setScale()方法设置保留几位小数以及保留规则。

BigDecimal m = new BigDecimal("1.255433");
BigDecimal n = m.setScale(3,RoundingMode.HALF_DOWN);
System.out.println(n);// 1.255
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hellosc01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值