浮点数存不准是因为十进制小数如0.1在二进制中为无限循环小数,ieee 754标准用有限位数截断存储导致近似;float精度6–7位,double精度15–17位;比较应使用误差容忍而非==。

浮点数为什么存不准
Java 的 float 和 double 本质是二进制近似表示,不是十进制精确值。像 0.1、0.2 这类常见小数,在二进制里是无限循环小数(如 0.1₁₀ = 0.0001100110011…₂),而内存空间有限,只能截断存储——这就注定是近似值。
IEEE 754 标准用“符号位 + 指数位 + 尾数位”三部分存数,例如 double:1 位符号、11 位指数、52 位尾数。它靠科学计数法(V = (−1)ˢ × M × 2ᴱ)平衡范围与精度,但不解决“十进制小数无法有限表达”的根本问题。
float 和 double 的关键区别
float 占 32 位(4 字节),约 6–7 位十进制精度;double 占 64 位(8 字节),约 15–17 位精度。日常开发中,double 是默认选择,除非明确受限于内存或性能(如图形批量计算)。
- 字面量如
3.14、0.5默认是 double 类型,直接赋给 float 变量会编译报错(类型不匹配) - 要声明 float 字面量,必须加后缀:
3.14f或3.14F - 2.5 能被精确表示(因为 0.5 = 1/2,二进制为有限小数),所以
2.5f == 2.5d返回 true;但 20.3 不行,20.3f == 20.3d为 false
避免浮点比较和误差累积
永远不要用 == 直接比较两个 float/double 值。哪怕只是简单加减,误差也可能暴露出来:
System.out.println(0.1 + 0.2); // 输出 0.30000000000000004
- 判断相等应改用“误差容忍”方式:
Math.abs(a - b) - 做累加、平均、比例运算时,误差会逐步放大,尤其在循环中反复操作
- 科学计算可接受一定误差,但金融、计费、配置校验等场景必须零容忍
高精度场景必须用 BigDecimal
当业务要求“绝对精确”,比如金额计算、利率复利、订单分账,必须用 java.math.BigDecimal。
- 构造时优先用字符串:
new BigDecimal("0.1"),避免new BigDecimal(0.1)(后者仍从 double 近似值构造) - 所有运算用方法调用:
add()、multiply()、divide()(注意指定舍入模式) - 不要用
BigDecimal做高频数学运算(如物理仿真),它比原生浮点慢得多,属于“精度换性能”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











