Java中float和double不是小数而是二进制科学计数法近似值,float约6–7位、double约15–17位有效数字,精度由尾数位决定,非小数点后位数;0.1+0.2≠0.3源于十进制小数在二进制中无限循环导致舍入误差,属IEEE 754标准设计本质,非Java独有bug。

Java 中的 float 和 double 不是“小数”,而是二进制科学计数法表示的近似值,精度限制源于 IEEE 754 标准的位数分配,不是 bug,而是设计本质。直接用 == 比较、做金融计算或累加小数,很容易出错。
float 和 double 的有效精度到底是多少
关键看尾数位(mantissa):
-
float:23 位尾数 → 约 6~7 位有效数字(不是小数点后几位,是整个数字的总位数)。比如
123456.7共 7 位,可能刚好保得住;但1234567.8(8 位)就大概率丢精度。 -
double:52 位尾数 → 约 15~17 位有效数字。例如
123456789012345.6这种 16 位总数的数,通常可准确表示;超过 17 位,就不可靠了。
注意:所谓“小数点后几位”是误导。精度取决于整数部分+小数部分的**总有效位数**。比如 0.0000001234567(共 7 位有效数字),float 可能存得准;但 123456789.0(9 位整数)用 float 就已超出精度上限。
为什么 0.1 + 0.2 ≠ 0.3
因为十进制的 0.1 在二进制中是无限循环小数:0.0001100110011…。float 和 double 只能截断存储,必然引入舍入误差。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
-
double a = 0.1; double b = 0.2;→a + b实际是0.30000000000000004 - 同理,
0.05 + 0.01得到0.060000000000000005,4.015 * 100得到401.49999999999994
这不是 Java 特有,而是所有遵循 IEEE 754 的语言(C/C++/Python/JS)共有的底层行为。
浮点比较和判断相等的正确做法
永远不要用 == 直接比较两个 float 或 double 值是否“数学相等”。
- ✅ 正确方式:用误差范围(epsilon)判断是否“足够接近”
Math.abs(a - b)(对double常用1e-10~1e-15;float一般用1e-6) - ✅ 工具类推荐:
Double.compare(a, b) == 0(用于排序或判等逻辑,内部也基于误差思想) - ❌ 错误写法:
a == 0.1、f == 1.0f、d >= 1.0(尤其在循环条件或 if 判断中)
什么时候该用 BigDecimal 而不是 double
当业务要求**精确十进制运算**时,double 再高精度也不够——它天生不擅长表示 0.1 这类常见小数。
- ✅ 必须用
BigDecimal的场景:
• 金额计算(如支付、账单、积分)
• 需要可控舍入模式(四舍五入、向上取整、银行家舍入)
• 高精度科学数据导出、审计日志 - ⚠️ 关键细节:
• 构造函数必须用String,不能用double:
new BigDecimal("12.35")✅
new BigDecimal(12.35)❌(此时传入的12.35本身已是二进制近似值)
• 所有运算用.add()、.multiply()等方法,不用+*

















