Java:双机器epsilon是不是最小的x这样1 + x!= 1? [英] Java: Double machine epsilon is not the smallest x such that 1+x != 1?

查看:588
本文介绍了Java:双机器epsilon是不是最小的x这样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 representable double value x such that 1.0 + x != 1.0, just as in C/C++. According to wikipedia, this machine epsilon is equal to 2^-52 (with 52 being the number of double 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 smallest x such that 1.0 + x != 1.0, there seems to be a smaller one, aka the previous double value according to 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));

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 -- that eps is not the smallest x with 1.0 + x != 1.0, but rather about twice that value: Adding 1.0 + Math.nextAfter(eps/2) is rounded up to 1.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 from 1.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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆