Java:双机器epsilon是不是最小的x这样1 + x!= 1? [英] Java: Double machine epsilon is not the smallest x such that 1+x != 1?
问题描述
我试图确定 double
机器epsilon Java,使用它的最小可表示定义 double
值 x
,使得 1.0 + x!= 1.0
,就像在C / C ++中一样。根据维基百科,这台机器epsilon等于 2 ^ -52
(其中52是 double
尾数位数 - 1)。
$ b
我的实现使用 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?真
到目前为止,这么好。但是,如果我检查给定的 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 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?假
正如我们所看到的,我们有一个小于机器的epsilon,加上1, 1,与定义相矛盾。
那么根据这个定义,机器ε的普遍接受的值有什么问题呢?还是我错过了什么?我怀疑浮点数学的另一个深奥的方面,但我不明白我去哪里错了...
编辑:感谢评论者,我终于明白了。我实际上使用了错误的定义! eps = Math.ulp(1.0)
计算距离最小的可表示的double> 1.0
,但是 - 这就是 eps
不是最小的 x
, 1.0 + x!= 1.0
,而是两次 $ c>被舍入 up 到 1.0 + eps
。
使用它的最小可表示双精度值x的定义,例如1.0 + x!= 1.0,就像在C / C ++中一样
< blockquote>
这个从来没有定义过,不是在Java中,也不是在C中,而不是在C ++中。
定义是即机器epsilon是一个和最小浮点数之间的距离/双大于一。
您的定义是错误近2倍。
另外,缺少
strictfp
只允许一个更大的指数范围,并且不应该对ε的经验测量产生任何影响,因为它是从1.0计算的。 code>及其后继者,其中的每一个都可以用标准指数范围表示。
I am trying to determine the
double
machine epsilon in Java, using the definition of it being the smallest representabledouble
valuex
such that1.0 + x != 1.0
, just as in C/C++. According to wikipedia, this machine epsilon is equal to2^-52
(with 52 being the number ofdouble
mantissa bits - 1).My implementation uses the
Math.ulp()
function:double eps = Math.ulp(1.0); System.out.println("eps = " + eps); System.out.println("eps == 2^-52? " + (eps == Math.pow(2, -52)));
and the results are what I expected:
eps = 2.220446049250313E-16 eps == 2^-52? true
So far, so good. However, if I check that the given
eps
is indeed the smallestx
such that1.0 + x != 1.0
, there seems to be a smaller one, aka the previousdouble
value according toMath.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));
Which yields:
epsPred = 2.2204460492503128E-16 epsPred < eps? true 1.0 + epsPred == 1.0? false
As we see, we have a smaller than machine epsilon such which, added to 1, yields not 1, in contradiction to the definition.
So what is wrong with the commonly accepted value for machine epsilon according to this definition? Or did I miss something? I suspect another esoteric aspect of floating-point maths, but I can't see where I went wrong...
EDIT: Thanks to the commenters, I finally got it. I actually used the wrong definition!
eps = Math.ulp(1.0)
computes the distance to the smallest representable double >1.0
, but -- and that's the point -- thateps
is not the smallestx
with1.0 + x != 1.0
, but rather about twice that value: Adding1.0 + Math.nextAfter(eps/2)
is rounded up to1.0 + eps
.解决方案using the definition of it being the smallest representable double value x such that 1.0 + x != 1.0, just as in C/C++
This has never been the definition, not in Java and not in C and not in C++.
The definition is that the machine epsilon is the distance between one and the smallest float/double larger than one.
Your "definition" is wrong by a factor of nearly 2.
Also, the absence of
strictfp
only allows a larger exponent range and should not have any impact on the empirical measurement of epsilon, since that is computed from1.0
and its successor, each of which and the difference of which can be represented with the standard exponent range.这篇关于Java:双机器epsilon是不是最小的x这样1 + x!= 1?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!