浮点数不适合财务计算,核心在于其二进制科学计数法无法精确表示十进制小数(如0.1),导致初始误差及运算中累积放大,而财务场景要求绝对精确、零偏差。

浮点数不适合财务计算,核心在于它根本不是为“精确表示十进制小数”而设计的——它的底层是二进制科学计数法,而日常金钱(如 0.1 元、0.01 元)在二进制中大多无法有限表达。
十进制小数在二进制中天然不精确
比如 0.1 元,换算成二进制是无限循环小数:
0.1 × 2 = 0.2 → 0
0.2 × 2 = 0.4 → 0
0.4 × 2 = 0.8 → 0
0.8 × 2 = 1.6 → 1
0.6 × 2 = 1.2 → 1
0.2 × 2 = 0.4 → 0(开始循环)
结果是 0.0001100110011…₂,永远除不尽。float(32 位)和 double(64 位)只能截断存储,必然引入初始误差。
误差会在运算中累积放大
单次误差可能微小,但加减乘除、循环累加等操作会让误差叠加甚至翻倍:
- 1.03 − 0.42 输出 0.6100000000000001,而不是准确的 0.61
- 1.00 − 9 × 0.10 得到 0.09999999999999998,少算了 0.00000000000000002 元
- 循环扣减场景(如买糖果):用 double 模拟找零,最后余额可能变成 0.3999999999999999,而非应得的 0.40
类型精度本身就不保障小数位安全
float 最多保证约 6–7 位有效数字,double 约 15–17 位——但这指的是“整体有效位”,不是“小数点后几位”:
- 12345678.9 这样的金额,已接近 float 整数精度上限(±16777216),再做小数运算极易失真
- 即便用 double,像 12.35 在内存中实际可能是 12.34444444444444449,转成 BigDecimal 后四舍五入反而变错
- 数据库层面,MySQL 的 FLOAT/DOUBLE 同样存在存取不一致问题,比如插入 2.888888 可能存为 2.889
财务场景容不得“近似正确”
银行账户、支付对账、发票金额、分润结算……所有环节都要求确定性、可复现、零偏差。哪怕单笔误差仅 0.00000001 元,百万级交易后就可能差出几百元;系统间比对时,一个 == 判断就会失败(如 0.1f + 0.2f != 0.3f)。
这不是代码写得不够好,而是 float/double 的数学本质决定它们不该出现在钱的计算里。










