BigDecimal高精度运算

1. BigDecimal是什么类型,为什么可以转为double

BigDecimal 是 Java 中用于表示任意精度的十进制数的类。它主要用于金融和商业计算,能够提供比 double 类型更高精度的运算,特别是在处理货币等需要精确计算的场景中。

1.1  BigDecimal 的基本性质

  • 高精度: BigDecimal 可以表示非常大或者非常小的十进制数,并且能够精确控制小数点后的位数。
  • 不可变: BigDecimal 类是不可变的,这意味着每次对 BigDecimal 对象进行操作时,都会返回一个新的 BigDecimal 对象,而不会改变原对象。
  • 构造方法: BigDecimal 可以通过字符串、doubleint 等多种方式来构造。例如:
BigDecimal bd1 = new BigDecimal("123.45"); // 通过字符串构造
BigDecimal bd2 = new BigDecimal(123.45);   // 通过double构造(不推荐,因为可能会导致精度问题)

1.2. 为什么可以转换为 double

BigDecimal 可以通过调用其 doubleValue() 方法将其转换为 double 类型。这是因为 BigDecimal 本质上是一个表示十进制数的对象,而 double 是 Java 的原始类型,用于表示双精度浮点数。

BigDecimal bd = new BigDecimal("123.45");
double d = bd.doubleValue(); // 将 BigDecimal 转换为 double

1.3. 转换的注意事项

虽然可以将 BigDecimal 转换为 double,但需要注意以下几点:

  • 精度丢失: double 的精度有限(大约 15-16 位有效数字),而 BigDecimal 可以精确到任意位数。因此,将 BigDecimal 转换为 double 时,可能会出现精度丢失的问题,特别是在处理非常大的数字或精度要求很高的场景时。
  • 浮点运算误差: 使用 double 进行运算时,可能会引入浮点运算误差,而 BigDecimal 在执行加减乘除等操作时可以保持精确。

1.4. 使用 doubleValue() 的场景

在某些情况下,尽管 BigDecimal 提供了更高精度,但仍需要将其转换为 double 类型,例如:

  • 与其他使用 double 的库或 API 进行交互:某些库或 API 可能要求使用 double 类型。
  • 计算后输出结果:在计算完成后,可能需要将结果输出为 double 类型以便于显示或进一步处理。

总之,BigDecimal 是一种用于高精度计算的数据类型,可以通过 doubleValue() 方法转换为 double,但在转换过程中应小心处理精度丢失和浮点运算误差的可能性。

2. 两个整数相除为什么能得到BigDecimal 类型

在 Java 中,两个整数相除通常会得到一个整数结果,但如果你希望得到一个高精度的结果并且避免精度丢失,可以使用 BigDecimal 类来进行除法运算。通过 BigDecimal 的除法操作,即使两个整数相除,结果也会保留小数部分,从而得到一个 BigDecimal 类型的结果。

2.1. NumberUtil.div 方法解析

NumberUtil.div 方法来自于 Hutool 工具包,是一个方便的工具方法,用于高精度的除法运算。其主要作用是将两个数(可以是整数、小数等)进行除法运算,并返回 BigDecimal 类型的结果。

例如,假设 volumecarriage.getLightThrowingCoefficient() 都是整数类型(例如 intlong),但通过 NumberUtil.div 进行除法运算时,会返回一个精确的 BigDecimal 结果,而不是简单地返回整数部分。

2.2. Hutool 的 NumberUtil.div 用法

NumberUtil.div 的用法通常如下:

public static BigDecimal div(Number v1, Number v2, int scale)
  • v1:被除数,可以是整数、浮点数、BigDecimal 等类型。
  • v2:除数,可以是整数、浮点数、BigDecimal 等类型。
  • scale:指定结果的小数位数,即结果精度。

2.3. 举例说明

假设 volume 是 10,carriage.getLightThrowingCoefficient() 是 3,你想要精确地计算这两个数的商并保留一位小数。通过 NumberUtil.div 进行除法运算会返回一个 BigDecimal 类型的结果。

int volume = 10;
int coefficient = 3;
BigDecimal volumeWeight = NumberUtil.div(volume, coefficient, 1);
  • 这个除法计算实际上是 10 / 3,结果是 3.3333...,但由于你指定了保留一位小数(scale 参数为 1),结果会被四舍五入为 3.3,并以 BigDecimal 类型返回。

2.4. BigDecimal 的除法

BigDecimal 本身也提供了非常强大的除法操作。如果不使用 NumberUtil.div,也可以直接使用 BigDecimal 进行计算:

BigDecimal volume = new BigDecimal(10);
BigDecimal coefficient = new BigDecimal(3);
BigDecimal volumeWeight = volume.divide(coefficient, 1, RoundingMode.HALF_UP);
  • divide 方法BigDecimaldivide 方法提供了高精度的除法运算。
  • 1 表示结果保留一位小数。
  • RoundingMode.HALF_UP 表示四舍五入。

2.5. 总结

当两个整数进行除法运算时,直接相除会丢弃小数部分,得到一个整数结果。然而,通过使用 BigDecimal 类或工具类方法(如 Hutool 的 NumberUtil.div),可以保留小数部分并得到一个精确的 BigDecimal 结果。这种方法特别适用于需要高精度计算的场景,例如财务、科学计算等。

3. 代码解释

/**************************
* 参数类型说明:
* volumes是Integer类型
* carriage.getLightThrowingCoefficient()是Integer类型
* waybillDTO.getWeight() 是double类型
**************************/

// 计算体积重量,体积 / 轻抛系数
BigDecimal volumeWeight = NumberUtil.div(volume, carriage.getLightThrowingCoefficient(), 1);

//取大值
double computeWeight = NumberUtil.max(volumeWeight.doubleValue(), NumberUtil.round(waybillDTO.getWeight(), 1).doubleValue());

这段代码的目的是根据包裹的体积和重量计算出实际的计费重量。它首先计算体积重量,然后在体积重量和实际重量之间取较大值作为最终的计费重量。

3.1 计算体积重量

BigDecimal volumeWeight = NumberUtil.div(volume, carriage.getLightThrowingCoefficient(), 1);
  • volumeWeight 是通过将包裹的体积除以一个称为“轻抛系数”的值计算出来的。
    • volume: 包裹的体积(通常是长、宽、高的乘积)。
    • carriage.getLightThrowingCoefficient(): 轻抛系数,这是一个常量,用来将体积转换为重量。通常,物流行业使用这个系数来计算体积重量,因为轻的、但体积大的包裹会占用更多的运输空间。
    • NumberUtil.div: 用于进行高精度的除法运算。
      • 第一个参数 volume 是被除数(体积)。
      • 第二个参数 carriage.getLightThrowingCoefficient() 是除数(轻抛系数)。
      • 第三个参数 1 表示结果保留一位小数。

体积重量的计算公式是: 体积重量=包裹体积/轻抛系数

3.2. 取较大值作为计费重量

double computeWeight = NumberUtil.max(volumeWeight.doubleValue(), NumberUtil.round(waybillDTO.getWeight(), 1).doubleValue());

computeWeight 计算包裹的最终计费重量,它取的是体积重量和实际重量中的较大值。

  • volumeWeight.doubleValue(): 将体积重量转换为 double 类型,以便与实际重量比较。
  • waybillDTO.getWeight(): 获取包裹的实际重量。
  • NumberUtil.round(waybillDTO.getWeight(), 1): 对实际重量进行四舍五入,保留一位小数。
  • NumberUtil.max: 比较两个数值,返回较大者。

注:NumberUtil.round 方法的作用是对数字进行四舍五入,并返回一个 BigDecimal 类型的结果。即使 waybillDTO.getWeight() 返回的是 double 类型,经过 NumberUtil.round 处理后,结果会变成 BigDecimal

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cyt涛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值