BigDecimal 的存储结构是什么样子的?
1 个回答
世间行乐亦如此,古来万事东流水。鬼木`BigDecimal` 是 Java 提供的**高精度浮点数运算**类,它的底层采用 **整数 (`BigInteger`) + 小数位数** 组合的方式存储数值。 ## **1. `BigDecimal` 的核心数据结构** ```java public class BigDecimal extends Number implements Comparable<BigDecimal> { private final BigInteger intVal; // 存储整数值 private final int scale; // 小数位数(即10的指数) private transient int precision; // 精度(有效数字位数) } ``` ### **🔹 `intVal`(核心值)** - 采用 `BigInteger` 存储**完整的整数值**,不包含小数点。 - **无固定范围**,可以存储**任意大小的整数部分**。 ### **🔹 `scale`(小数位数)** - `scale` 表示**小数位数**,也就是**整数值 `intVal` 需要除以 `10^scale`** 才能得到最终的 `BigDecimal` 值。 - `scale = 0` 时,`BigDecimal` 代表整数。 ### **🔹 `precision`(精度)** - 计算 `BigDecimal` 的**有效位数**(所有非零数字)。 - 这个字段不是直接存储,而是动态计算的。 ## **2. `BigDecimal` 的存储示例** ### **示例 1:存储 `123.45`** ```java BigDecimal bd = new BigDecimal("123.45"); ``` - `intVal = 12345` (整数存储) - `scale = 2` (需要除以 `10^2`) - `precision = 5` (`12345` 的有效数字) > **实际值计算**: > ``` > 12345 / 10^2 = 123.45 > ``` ### **示例 2:存储 `0.00123`** ```java BigDecimal bd = new BigDecimal("0.00123"); ``` - `intVal = 123`(去掉小数点) - `scale = 5`(除以 `10^5`) - `precision = 3`(`123` 有 3 位) > **实际值计算**: > ``` > 123 / 10^5 = 0.00123 > ``` ### **示例 3:存储 `100.0`** ```java BigDecimal bd = new BigDecimal("100.0"); ``` - `intVal = 1000` - `scale = 1` - `precision = 4` > **注意**:即使 `100.0` 和 `100` 代表相同数值,但 `scale` 和 `precision` 仍然不同。 ## **3. `BigDecimal` 的运算** 由于 `BigDecimal` 采用 `BigInteger` 存储,所以所有运算都基于**整数运算**,然后再调整 `scale`。 ### **🔹 加法 (`add()`)** - 先 **统一 `scale`**(小数位对齐)。 - `BigInteger` 相加。 - 结果保持较大的 `scale`。 ```java BigDecimal a = new BigDecimal("1.23"); BigDecimal b = new BigDecimal("0.007"); BigDecimal sum = a.add(b); System.out.println(sum); // 1.237 ``` 底层计算: ``` 123 × 10^-2 + 7 × 10^-3 = 1230 × 10^-3 + 7 × 10^-3 = 1237 × 10^-3 = 1.237 ``` ### **🔹 乘法 (`multiply()`)** - `intVal` 直接相乘。 - `scale` 相加。 ```java BigDecimal a = new BigDecimal("1.2"); // scale = 1 BigDecimal b = new BigDecimal("3.45"); // scale = 2 BigDecimal result = a.multiply(b); System.out.println(result); // 4.14 ``` 底层计算: ``` 12 × 345 = 4140 scale = 1 + 2 = 3 4140 × 10^-3 = 4.14 ``` ### **🔹 除法 (`divide()`)** - `intVal` 除法(可能有余数)。 - `scale` 调整(通常 `ROUND_HALF_UP` 处理小数位)。 ```java BigDecimal a = new BigDecimal("10"); BigDecimal b = new BigDecimal("3"); BigDecimal result = a.divide(b, 5, RoundingMode.HALF_UP); System.out.println(result); // 3.33333 ``` 底层计算: ``` 10 ÷ 3 = 3.33333 (保留 5 位小数) ``` ## **4. `BigDecimal` 与 `double` 的对比** | **特性** | **BigDecimal** | **double** | |----------|--------------|------------| | 存储方式 | `BigInteger` + `scale` | IEEE 754 二进制浮点 | | 精度 | **任意精度** | **大约 15-16 位** | | 计算方式 | **精确数学运算** | **二进制浮点计算(可能丢失精度)** | | 适用场景 | **金融计算、货币** | **科学计算、快速近似计算** | ### **🔹 `double` 精度丢失问题** ```java System.out.println(0.1 + 0.2); // 0.30000000000000004 ``` **原因**: - `0.1` 和 `0.2` **无法用二进制精确表示**,导致**累积误差**。 **解决方案**: ```java BigDecimal a = new BigDecimal("0.1"); BigDecimal b = new BigDecimal("0.2"); BigDecimal sum = a.add(b); System.out.println(sum); // 0.3 ``` **`BigDecimal` 保证计算精度,避免浮点误差。** ## **5. 总结** ✅ **存储结构:`BigInteger` + `scale`,支持任意精度** ✅ **运算基于 `BigInteger`,避免浮点精度误差** ✅ **适用于金融计算,但比 `double` 慢**发布于 2025-03-17 14:19 •IP属地 湖南举报评论收藏
公众号进入网站体验更佳

