0.1f != 0.1 是因二进制浮点表示无法精确表达十进制0.1,float尾数23位精度低于double的52位,导致两者存储值不同;所有IEEE 754语言均如此。

为什么 0.1f != 0.1 ?浮点数二进制存储导致的精度丢失
因为 float 和 double 都遵循 IEEE 754 标准,用二进制表示十进制小数时,很多数(比如 0.1、0.2)根本无法精确表达——它们在内存里就是近似值。float 只有 23 位尾数,double 有 52 位,所以 0.1f 的误差比 0.1(即 0.1d)大得多。
- float 存
0.1f实际是0.10000000149011612 - double 存
0.1实际是0.1000000000000000055511151231257827021181583404541015625 - 这不是 Java 的 bug,所有遵循 IEEE 754 的语言(Python、C、JavaScript)都一样
什么时候必须用 double 而不能用 float ?
绝大多数日常场景下,double 是更安全的选择;float 只在明确需要节省内存且能接受精度妥协时才用。
- 金融计算、科学计算、坐标运算(如
lat/lng)、时间戳差值:必须用double,float在几万次加减后误差可能达 0.01 级别 - 图形渲染、GPU 计算、大量数组缓存(如百万级顶点数据):可考虑
float,因显卡和部分 SIMD 指令对单精度更友好 - Android 上
Canvas绘图 API 接收的是float,但那是接口契约,不是精度推荐——内部仍建议用double做逻辑计算,最后转float传入
“== 比较失败”怎么修?别直接用 == 判断浮点数相等
这是最常踩的坑:0.1f + 0.2f == 0.3f 返回 false,0.1 + 0.2 == 0.3 同样是 false。因为它们存储的都不是数学意义上的“0.3”。
- 正确做法是用误差范围(epsilon)比较:
Math.abs(a - b) - Java 无内置
equals浮点比较工具,别依赖Float.equals()或Double.equals()——它们对NaN行为特殊,且仍基于位比较 - 若涉及业务逻辑判断(如“是否到账 100.0 元”),应改用
BigDecimal,而不是调高 epsilon
float 字面量写错会编译失败:Java 默认把小数当 double
写 float f = 3.14; 直接报错:“possible loss of precision”,因为 3.14 是 double 字面量,不能隐式转 float。
立即学习“Java免费学习笔记(深入)”;
- 必须显式标注:
float f = 3.14f;或float f = (float) 3.14; -
double d = 3.14d;合法但冗余,d后缀可省略;f后缀不可省 - 科学计数法同理:
1.23E-4f✅,1.23E-4❌(赋给float变量时)
真正容易被忽略的点是:精度问题不只出现在“结果看起来不对”时,它会悄悄累积——比如循环中不断 sum += 0.1f,到第 100 次时误差已不可忽视。这时候换 double 只是延缓问题,关键得看场景要不要用 BigDecimal 或整型缩放(如金额存分为单位)。










