CrabNote螃蟹笔记

BigDecimal 详解

《阿里巴巴 Java 开发手册》中提到:“为了避免精度丢失,可以使用 `BigDecimal` 来进行浮点数的运算”。 浮点数的运算竟然还会有精度丢失的风险吗?确实会! 示例代码: ```tex

《阿里巴巴 Java 开发手册》中提到:“为了避免精度丢失,可以使用 来进行浮点数的运算”。 浮点数的运算竟然还会有精度丢失的风险吗?确实会! 示例代码: 为什么浮点数 或 运算的时候会有精度丢失的风险呢? 这个和计算机保存小数的机制有很大关系。我们知道计算机是二进制的,而且计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。这也就解释了为什么十进制小数没有办法用二进制精确表示。 就比如说十进制下的 0.2 就没办法精确转换成二进制小数: 关于浮点数的更多内容,建议看一下计算机系统基础(四)浮点数这篇文章。 BigDecimal 介绍 可以实现对小数的运算,不会造成精度丢失。 通常情况下,大部分需要小数精确运算结果的业务场景(比如涉及到钱的场景)都是通过 来做的。 《阿里巴巴 Java 开发手册》中提到: 浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能用 equals 来判断。 具体原因我们在上面已经详细介绍了,这里就不多提了。 想要解决浮点数运算精度丢失这个问题,可以直接使用 来定义小数的值,然后再进行小数的运算操作即可。 BigDecimal 常见方法 创建 我们在使用 时,为了防止精度丢失,推荐使用它的 构造方法或者 静态方法来创建对象。 《阿里巴巴 Java 开发手册》对这部分内容也有提到,如下图所示。 加减乘除 方法用于将两个 对象相加, 方法用于将两个 对象相减。 方法用于将两个 对象相乘, 方法用于将两个 对象相除。 这里需要注意的是,在我们使用 方法的时候尽量使用 3 个参数版本,并且 不要选择 ,否则很可能会遇到 (无法除尽出现无限循环小数的时候),其中 表示要保留几位小数, 代表保留规则。 保留规则非常多,这里列举几种: 大小比较 : 返回 1 表示 小于 ,0 表示 等于 , 1 表示 大于 。 保留几位小数 通过 方法设置保留几位小数以及保留规则。保留规则有挺多种,不需要记,IDEA 会提示。 BigDecimal 等值比较问题 《阿里巴巴 Java 开发手册》中提到: 使用 方法进行等值比较出现问题的代码示例: 这是因为 方法不仅仅会比较值的大小(value)还会比较精度(scale),而 方法比较的时候会忽略精度。 1.0 的 scale 是 1,1 的 scale 是 0,因此 的结果是 false。 方法可以比较两个 的值,如果相等就返回 0,如果第 1 个数比第 2 个数大则返回 1,反之返回 1。 BigDecimal 工具类分享 网上有一个使用人数比较多的 工具类,提供了多个静态方法来简化 的操作。 我对其进行了简单改进,分享一下源码: 相关 issue:建议对保留规则设置为 RoundingMode.HALF\ EVEN,即四舍六入五成双, 2129。 总结 浮点数没有办法用二进制精确表示,因此存在精度丢失的风险。 不过,Java 提供了 来操作浮点数。 的实现利用到了 (用来操作大整数), 所不同的是 加入了小数位的概念。 写在最后 如果内容对你有帮助的话,欢迎顺手给 JavaGuide 点一个免费的 Star 支持一下:GitHub | Gitee。 JavaGuide 已持续维护近七年,累计 6100+ 次提交,来自 620+ 位贡献者共同完善。你的 Star、反馈和 PR,都是这个项目继续更新的动力。 如果你正在准备后端/AI 应用开发面试,也可以了解一下我的知识星球,里面包括后端和 AI 实战项目、简历优化、一对一提问和高频考点资料,已经持续维护六年。