Java:双机epsilon不是最小的x,1 + x != 1?
我试图确定Java中的机器epsilon,使用它是最小可表示值的定义,就像在C / C++一样。根据维基百科,这台机器epsilon等于(52是尾数位数- 1)。double
double
x
1.0 + x != 1.0
2^-52
double
我的实现使用函数: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
double
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