news 2026/4/18 8:52:57

BigDecimal除法异常:Non-terminating decimal expansion 解决方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
BigDecimal除法异常:Non-terminating decimal expansion 解决方案

问题描述

在使用BigDecimal进行精确计算时,特别是进行除法运算时,可能会遇到以下异常:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

异常原因

BigDecimal是不可变的、任意精度的有符号十进制数,专为精确计算设计。但在除法运算中,当除不尽时(商是无限循环小数,如1除以3),如果没有指定舍入规则,BigDecimal无法精确表示结果,因此抛出此异常。

解决方案

方案1:使用divide()方法时指定舍入模式(推荐)

import java.math.BigDecimal; import java.math.RoundingMode; public class BigDecimalExample { public static void main(String[] args) { BigDecimal dividend = new BigDecimal("1"); BigDecimal divisor = new BigDecimal("3"); // 指定舍入模式(四舍五入,保留2位小数) BigDecimal result = dividend.divide(divisor, 2, RoundingMode.HALF_UP); System.out.println(result); // 输出: 0.33 // 其他舍入模式示例 // 向上取整 BigDecimal result2 = dividend.divide(divisor, 2, RoundingMode.UP); // 向下取整 BigDecimal result3 = dividend.divide(divisor, 2, RoundingMode.DOWN); // 银行家舍入法(四舍六入五成双) BigDecimal result4 = dividend.divide(divisor, 2, RoundingMode.HALF_EVEN); } }

方案2:使用MathContext指定精度

import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; public class BigDecimalExample2 { public static void main(String[] args) { BigDecimal dividend = new BigDecimal("1"); BigDecimal divisor = new BigDecimal("3"); // 使用MathContext指定精度和舍入模式 MathContext mc = new MathContext(4, RoundingMode.HALF_UP); BigDecimal result = dividend.divide(divisor, mc); System.out.println(result); // 输出: 0.3333 } }

常用舍入模式详解

舍入模式描述示例(保留0位小数)
RoundingMode.UP远离零方向舍入2.5 → 3, -2.5 → -3
RoundingMode.DOWN向零方向舍入2.5 → 2, -2.5 → -2
RoundingMode.CEILING向正无穷方向舍入2.5 → 3, -2.5 → -2
RoundingMode.FLOOR向负无穷方向舍入2.5 → 2, -2.5 → -3
RoundingMode.HALF_UP四舍五入2.5 → 3, -2.5 → -3
RoundingMode.HALF_DOWN五舍六入2.5 → 2, 2.6 → 3
RoundingMode.HALF_EVEN银行家舍入法2.5 → 2, 3.5 → 4

实际业务场景选择建议

1. 金融计算(金额处理)

// 金额计算通常需要保留2位小数,使用四舍五入 BigDecimal amount = price.divide(quantity, 2, RoundingMode.HALF_UP);

2. 科学计算

// 科学计算可能需要更高精度 BigDecimal result = value1.divide(value2, 10, RoundingMode.HALF_UP);

3. 比例计算

// 百分比计算,保留4位小数 BigDecimal percentage = part.divide(total, 4, RoundingMode.HALF_UP) .multiply(new BigDecimal("100"));

最佳实践

  1. 始终在除法运算中指定舍入模式,避免潜在的异常

  2. 根据业务需求选择合适的精度和舍入模式

  3. 金额计算统一使用2位小数精度

  4. 使用字符串构造函数创建BigDecimal,避免精度丢失

// 推荐 BigDecimal d1 = new BigDecimal("0.1"); // 不推荐(可能丢失精度) BigDecimal d2 = new BigDecimal(0.1);

工具类示例

import java.math.BigDecimal; import java.math.RoundingMode; public class BigDecimalUtils { // 默认金融计算精度(2位小数) private static final int DEFAULT_SCALE = 2; /** * 安全的除法运算(使用默认精度和四舍五入) */ public static BigDecimal safeDivide(BigDecimal dividend, BigDecimal divisor) { if (divisor.compareTo(BigDecimal.ZERO) == 0) { throw new ArithmeticException("除数不能为零"); } return dividend.divide(divisor, DEFAULT_SCALE, RoundingMode.HALF_UP); } /** * 安全的除法运算(自定义精度和舍入模式) */ public static BigDecimal safeDivide(BigDecimal dividend, BigDecimal divisor, int scale, RoundingMode roundingMode) { if (divisor.compareTo(BigDecimal.ZERO) == 0) { throw new ArithmeticException("除数不能为零"); } return dividend.divide(divisor, scale, roundingMode); } /** * 百分比计算 */ public static BigDecimal calculatePercentage(BigDecimal part, BigDecimal total) { BigDecimal ratio = safeDivide(part, total, 4, RoundingMode.HALF_UP); return ratio.multiply(new BigDecimal("100")); } }

总结

Non-terminating decimal expansion异常的根本原因是BigDecimal除法运算中无限小数的存在。解决此问题的关键在于:

  1. 必须在调用divide()方法时指定精度和舍入模式

  2. 根据业务场景选择合适的舍入策略

  3. 金融计算通常使用HALF_UP(四舍五入)模式

  4. 建议封装工具类统一处理BigDecimal运算

遵循这些原则,可以确保BigDecimal计算的精确性和稳定性,避免运行时异常的发生。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:51:16

HunyuanVideo-Foley播客应用:为音频节目自动添加背景音

HunyuanVideo-Foley播客应用:为音频节目自动添加背景音 1. 技术背景与应用场景 随着数字内容创作的爆发式增长,音频节目、播客、短视频等内容形式对制作效率和沉浸感提出了更高要求。传统音效制作依赖人工剪辑与素材库匹配,耗时长、成本高&…

作者头像 李华
网站建设 2026/4/17 22:54:16

零基础教程:5步学会制作炫酷3D饼图

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个适合新手的3D饼图教学示例。展示一周七天的时间分配:工作40%,学习20%,娱乐15%,运动10%,休息15%。要求&#xff…

作者头像 李华
网站建设 2026/4/17 21:25:17

对比测试:MELIS3.0开发效率提升300%的秘密

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 构建一个对比测试项目:1. 传统方式开发MELIS3.0串口通信模块;2. 使用InsCode平台AI辅助开发相同功能。要求:记录各阶段耗时,统计代码…

作者头像 李华
网站建设 2026/4/18 6:11:35

用SA-TOKEN快速验证产品创意:1小时打造可演示的认证原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个可演示的SA-TOKEN原型系统,要求:1. 集成SA-TOKEN到空白Spring Boot项目 2. 实现3种用户角色 5. 提供5个API接口 4. 包含基础前端演示页面 5. 一键D…

作者头像 李华
网站建设 2026/4/17 22:50:27

KIMI+零基础入门指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个KIMI学习应用,提供交互式教程和新手友好的界面。点击项目生成按钮,等待项目生成完整后预览效果 今天想和大家分享一下我最近用KIMI开发学习应用的心…

作者头像 李华
网站建设 2026/4/18 8:54:54

告别手动调整!Smart Doc Scanner一键搞定文档扫描与增强

告别手动调整!Smart Doc Scanner一键搞定文档扫描与增强 1. 背景与痛点:传统文档扫描的效率瓶颈 在日常办公、学习或合同处理中,我们经常需要将纸质文档、发票、白板笔记等转换为电子版。虽然智能手机已经普及,但直接拍摄的照片…

作者头像 李华