当前位置: 首页 > news >正文

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

http://www.lryc.cn/news/425128.html

相关文章:

  • C/C++实现蓝屏2.0
  • Unity音频管理器插件AudioToolKit
  • 搜维尔科技:驾驶模拟器背后的技术: Varjo的虚拟/混合现实 (VR/XR)提供独特的优势,最终加快汽车开发创新的步伐
  • OSL 冠名赞助Web3峰会 “FORESIGHT2024”圆满收官
  • LeetCode 3148.矩阵中的最大得分:每个元素与其左或上元素之差的最大值(原地修改O(1)空间)
  • 主流的开源大型语言模型
  • 【自动驾驶】话题通信
  • 【Linux】中的软件安装:深入探索RPM、SRPM与YUM
  • uniapp自定义请求头信息header
  • SpringBoot整合Liquibase
  • 虚幻5|给武器添加碰撞检测与伤害
  • RESTful API设计指南:构建高效、可扩展的Web服务
  • 黑马头条vue2.0项目实战(九)——编辑用户资料
  • 43.【C语言】指针(重难点)(F)
  • 【STM32+HAL】杆球控制系统
  • 用Python实现9大回归算法详解——04. 多项式回归算法
  • vue打包更新packge.json版本号
  • 计算机视觉技术解析:从基础到前沿
  • unity游戏开发003:深入理解Unity中的坐标系
  • 伊索寓言两则
  • 嵌入式硬件产品开发:编码文件规则
  • 设计模式 - 组合模式
  • 打靶记录11——Billu_b0x
  • 一、在cubemx上配置sd和fatfs示例演示
  • C++ 语言特性02 - 命名空间
  • drools规则引擎 规则配置文件drl语法使用案例
  • C++编程:高性能通信组件Capnproto与Protobuf的对比分析
  • 【Python读书数据,并计算数据的相关系数、方差,均方根误差】
  • 垃圾收集器G1ZGC详解
  • AI芯片:高性能卷积计算中的数据复用