BigDecimal
核心概念
BigDecimal是Java中用于精确计算的类,主要解决浮点数运算的精度问题。在金融、电商等对精度要求高的场景中必须使用。
一、为什么需要BigDecimal?
1.1 浮点数精度问题
// 浮点数运算的精度丢失
System.out.println(0.1 + 0.2); // 0.30000000000000004
System.out.println(1.0 - 0.9); // 0.09999999999999998
System.out.println(0.1 * 0.1); // 0.010000000000000002
// 比较问题
System.out.println(0.1 + 0.2 == 0.3); // false
1.2 原因分析
- 计算机使用二进制存储浮点数
- 0.1在二进制中是无限循环小数
- 存储时必须截断,导致精度丢失
0.1 (十进制) = 0.0001100110011... (二进制,无限循环)
1.3 BigDecimal的解决方案
// ✅ 解决方案:比较时使用误差范围
double epsilon = 1e-10;
System.out.println(Math.abs(d1 - 0.3) < epsilon); // true ✅
// 更佳:使用BigDecimal
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal c = a.add(b);
System.out.println(c); // 0.3(精确)
二、BigDecimal的创建
2.1 构造方法对比
// ❌ 错误:使用double构造(精度丢失)
BigDecimal bad = new BigDecimal(0.1);
System.out.println(bad); // 0.1000000000000000055511151231257827021181583404541015625
// ✅ 正确:使用String构造
BigDecimal good = new BigDecimal("0.1");
System.out.println(good); // 0.1
// ✅ 正确:使用valueOf(内部转String)
BigDecimal better = BigDecimal.valueOf(0.1);
System.out.println(better); // 0.1
2.2 构造方法选择
| 方式 | 精度 | 推荐度 |
|---|---|---|
new BigDecimal(double) |
❌ 有精度问题 | 不推荐 |
new BigDecimal(String) |
✅ 精确 | 推荐 |
BigDecimal.valueOf(double) |
✅ 精确 | 推荐 |
new BigDecimal(int/long) |
✅ 精确 | 推荐 |
2.3 常用常量
BigDecimal.ZERO; // 0
BigDecimal.ONE; // 1
BigDecimal.TEN; // 10
三、BigDecimal运算
3.1 四则运算
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("3");
// 加法
BigDecimal sum = a.add(b); // 13.5
// 减法
BigDecimal diff = a.subtract(b); // 7.5
// 乘法
BigDecimal product = a.multiply(b); // 31.5
// 除法(必须指定精度和舍入模式)
BigDecimal quotient = a.divide(b, 2, RoundingMode.HALF_UP); // 3.50
3.2 除法的特殊处理
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
// ❌ 错误:不指定精度,除不尽会抛异常
a.divide(b); // ArithmeticException: Non-terminating decimal expansion
// ✅ 正确:指定精度和舍入模式
a.divide(b, 2, RoundingMode.HALF_UP); // 3.33
a.divide(b, 4, RoundingMode.HALF_UP); // 3.3333
3.3 舍入模式(RoundingMode)
| 模式 | 说明 | 示例(保留1位) |
|---|---|---|
HALF_UP |
四舍五入 | 2.5→3, 2.4→2 |
HALF_DOWN |
五舍六入 | 2.5→2, 2.6→3 |
HALF_EVEN |
银行家舍入 | 2.5→2, 3.5→4 |
UP |
远离零方向舍入 | 2.1→3, -2.1→-3 |
DOWN |
向零方向舍入(截断) | 2.9→2, -2.9→-2 |
CEILING |
向正无穷舍入 | 2.1→3, -2.9→-2 |
FLOOR |
向负无穷舍入 | 2.9→2, -2.1→-3 |
UNNECESSARY |
不需要舍入,否则异常 | 2.0→2 |
BigDecimal value = new BigDecimal("2.5");
value.setScale(0, RoundingMode.HALF_UP); // 3(四舍五入)
value.setScale(0, RoundingMode.HALF_DOWN); // 2(五舍六入)
value.setScale(0, RoundingMode.HALF_EVEN); // 2(银行家舍入)
value.setScale(0, RoundingMode.UP); // 3(远离零)
value.setScale
⬅️ StringBuilder系列 🏠 00-Java ➡️ 04-Java时间新API
💬 评论