【发布时间】:2015-04-28 21:15:53
【问题描述】:
我正在尝试确定 Java 中的 double machine epsilon,使用它的定义是最小的可表示 double 值 x 这样 1.0 + x != 1.0,就像在 C/C++ 中一样。根据维基百科,这台机器 epsilon 等于 2^-52(其中 52 是 double 尾数位的数量 - 1)。
我的实现使用了Math.ulp() 函数:
double eps = Math.ulp(1.0);
System.out.println("eps = " + eps);
System.out.println("eps == 2^-52? " + (eps == Math.pow(2, -52)));
结果如我所愿:
eps = 2.220446049250313E-16
eps == 2^-52? true
到目前为止,一切都很好。但是,如果我检查给定的eps 确实是最小的 x 使得1.0 + x != 1.0,似乎有一个更小的,也就是previous @ 987654334@值根据Math.nextAfter():
double epsPred = Math.nextAfter(eps, Double.NEGATIVE_INFINITY);
System.out.println("epsPred = " + epsPred);
System.out.println("epsPred < eps? " + (epsPred < eps));
System.out.println("1.0 + epsPred == 1.0? " + (1.0 + epsPred == 1.0));
产量:
epsPred = 2.2204460492503128E-16
epsPred < eps? true
1.0 + epsPred == 1.0? false
正如我们所见,我们有一个小于机器的 epsilon,它加到 1 后得到的不是 1,这与定义相矛盾。
那么根据这个定义,机器 epsilon 的普遍接受值有什么问题?还是我错过了什么?我怀疑浮点数学的另一个深奥方面,但我看不出我哪里出错了......
编辑:感谢评论者,我终于明白了。我实际上使用了错误的定义! eps = Math.ulp(1.0) 计算到最小可表示双精度 > 1.0 的距离,但是——这就是重点——eps 不是最小的 x 和 1.0 + x != 1.0,而是大约 两倍 该值:将 1.0 + Math.nextAfter(eps/2) 添加到 向上 到 1.0 + eps。
【问题讨论】:
-
你试过
strictfp吗? -
是的,
strictfp在这里没有帮助。
标签: java floating-point epsilon