You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中double加减相同数值为何出现精度误差?

为什么double运算中(d1+d2-d2-d1)会产生精度误差?

由于浮点数精度限制,Java的double类型无法精确表示所有十进制数,会引入精度误差。给定如下代码:

double d1=0.20976190476190476;
double d2=0.062142857142857146;
System.out.println("d1-d1= "+(d1-d1)); //输出0.0。
System.out.println("d1+d2-d2-d1= "+(d1+d2-d2-d1)); //输出2.7755575615628914E-17

疑问:为何最后一行会产生精度误差?原以为表达式会按((d1+d2)-d2)-d1的顺序计算,即便d1、d2或d1+d2无法精确表示,精度误差也会相互抵消?


原因解析

  1. 浮点数的本质是二进制近似:
    double类型采用IEEE 754标准存储,只能精确表示有限的十进制数。你定义的d1和d2的十进制值转成二进制是无限循环的,所以实际存储的是它们最接近的近似二进制浮点数(记为D1和D2),并非原始十进制值。

  2. 每一步运算都可能引入舍入误差:

    • 第一步计算D1+D2:两个近似值相加的结果,会被舍入到最接近的double值(记为S),这里已经引入了一次舍入误差ε1,即S = D1+D2 + ε1。
    • 第二步计算S-D2:此时结果是D1 + ε1,但这个值不一定能被double精确表示,会再次被舍入到最接近的double值(记为D1'),又引入了二次舍入误差ε2,即D1' = D1 + ε1 + ε2。
    • 第三步计算D1' - D1:结果就是ε1+ε2,也就是你看到的2.7755575615628914E-17。
  3. 为什么d1-d1是0.0?
    IEEE 754标准规定,相同的double值相减结果精确为0.0,因为操作数完全一致,没有舍入差异,所以误差直接抵消。但(d1+d2)-d2得到的并不是原始的d1近似值,两次舍入的误差无法完全抵消,最终就出现了微小的差值。


内容的提问来源于stack exchange,提问作者Joris Kinable

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:35:21