java中float和double按ieee 754标准以二进制编码,由符号位、指数位(float 8位/bias=127,double 11位/bias=1023)和尾数位(float 23位、double 52位,隐含前导1)构成,导致0.1等十进制小数无法精确表示,运算产生误差,故不可用==比较,需用误差容忍或bigdecimal。

Java 中的 float 和 double 类型不是“带小数点的数字”那么简单,它们是严格按 IEEE 754 标准在内存中编码的二进制结构。理解这一点,才能真正明白为什么 0.1 + 0.2 != 0.3、为什么不能用 == 直接比较浮点数、以及如何合理选择精度和处理边界值。
IEEE 754 的三段式结构
所有遵循该标准的浮点数,无论语言或平台,都拆成三个固定字段:
- 符号位(1 bit):最高位,0 表示正,1 表示负;
- 指数位(Exponent):float 占 8 位(偏移量 Bias = 127),double 占 11 位(Bias = 1023);实际指数 = 存储值 − Bias;
- 尾数位(Fraction / Mantissa):float 23 位,double 52 位;存储的是科学计数法中“1.xxx”小数点后的部分,整数位的 1 是隐含的,不占存储空间,这叫“规格化表示”,多省出 1 位精度。
为什么 0.1 无法精确存储?
关键不在 Java,而在二进制表达能力本身:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 十进制小数 0.1 转二进制是无限循环小数:
0.0001100110011…₂(循环节 0011); - float 只能保留前 23 位尾数,必须截断或舍入 → 得到一个近似值;
- double 虽有 52 位尾数,仍无法终止该循环 → 仍是近似值;
- 两个近似值相加,误差不会抵消,反而可能放大,结果就是
0.30000000000000004。
float 与 double 的实际差异
区别不是“更精确”,而是位宽分配带来的能力差异:
-
范围不同:float 指数 8 位 → 最大约
3.4 × 10³⁸;double 指数 11 位 → 最大约1.8 × 10³⁰⁸; - 精度不同:float 尾数 23 位 → 约 6–7 位十进制有效数字;double 尾数 52 位 → 约 15–17 位;
- 适用场景不同:图形计算、传感器数据常用 float(节省内存/带宽);金融、科学计算必须用 double 或 BigDecimal(避免累积误差)。
Java 中的特殊值与安全实践
IEEE 754 明确定义了非数值状态,Java 完全支持:
-
±0.0:符号不同但值相等(0.0 == -0.0为 true); -
±Infinity:如1.0 / 0.0→Infinity; -
NaN(Not-a-Number):如0.0 / 0.0或Math.sqrt(-1);注意NaN != NaN,必须用Double.isNaN()判断; -
比较务必用误差容忍:用
Math.abs(a - b) 替代 <code>a == b;ε 通常取1e-6(float)或1e-15(double); -
金融运算禁用 float/double:应使用
BigDecimal,它基于十进制字符串构造,避免二进制近似问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










