我正在试图找到一些Java代码来确定两个双倍是否几乎相等。我做了很多谷歌搜索,并找到了零碎,我已经放在这里。它开始逃离我的地方是使用“相对感受器”。这个方法看起来就像我要找的。我不想直接指定epsilon,但是我想根据这两个参数的大小使用epsilon。这是我整理的代码,我需要检查一下。(P.S.我知道的数学刚刚够危险的。)
public class MathUtils
{
// http://stackoverflow.com/questions/3728246/what-should-be-the-
// epsilon-value-when-performing-double-value-equal-comparison
// ULP = Unit in Last Place
public static double relativeEpsilon( double a, double b )
{
return Math.max( Math.ulp( a ), Math.ulp( b ) );
}
public static boolean nearlyEqual( double a, double b )
{
return nearlyEqual( a, b, relativeEpsilon( a, b ) );
}
// http://floating-point-gui.de/errors/comparison/
public static boolean nearlyEqual( double a, double b, double epsilon )
{
final double absA = Math.abs( a );
final double absB = Math.abs( b );
final double diff = Math.abs( a - b );
if( a == b )
{
// shortcut, handles infinities
return true;
}
else if( a == 0 || b == 0 || absA + absB < Double.MIN_NORMAL )
{
// a or b is zero or both are extremely close to it
// relative error is less meaningful here
// NOT SURE HOW RELATIVE EPSILON WORKS IN THIS CASE
return diff < ( epsilon * Double.MIN_NORMAL );
}
else
{
// use relative error
return diff / Math.min( ( absA + absB ), Double.MAX_VALUE ) < epsilon;
}
}
}发布于 2017-04-07 22:48:46
我会为此使用一个库,我通常使用的是谷歌番石榴图书馆的DoubleMath库。https://google.github.io/guava/releases/19.0/api/docs/com/google/common/math/DoubleMath.html
if (DoubleMath.fuzzyEquals(a, b, epsilon)) { // a and b are equal within the tolerance given }还有一个fuzzyCompare。
发布于 2017-04-08 05:25:52
比较两个浮动值a,b的常用方法是:
if ( Math.abs(a-b) <= epsilon ) do_stuff_if_equal;
else do_stuff_if_different;其中Math.abs()是绝对值。由于我不使用JAVA编写代码,如果情况并非如此,则需要使用double变体。epsilon是你的不同之处。正如前面提到的,ulp太小了,无法做到这一点。您需要使用对您正在比较的值有意义的值。那么如何计算epsilon呢?
这有点棘手,是的,可以使用a,b的大小,但这不是一种健壮的方法,因为如果a,b的指数太不同,您可以很容易地获得假阳性。相反,你应该使用一个意义-完整的价值。例如,如果您正在比较位置坐标,那么epsilon应该是最小细节的分数,或者是您认为是相同点的最小距离。对于角度,一些很小的角度,比如1e-6 deg,但是这个值取决于你所使用的范围和精度。对于规范化的<-1,1>范围,我通常使用1e-10或1e-30。
正如你所看到的,epsilon主要取决于目标的精确性和大小,并且在不同的情况下都有很大的变化,所以创建一些统一的方法(像您想要的那样摆脱epsilon )是不安全的,只会导致以后的头部疼痛。
为了简化这一点,我通常定义一个可以更改的_zero常量或变量(在计算类的情况下)。将其设置为默认值,这对大多数情况都足够好,如果在某一时刻引起问题,我知道我可以很容易地更改它……
如果您想按自己的方式做(忽略上面的文本),那么您可以这样做:
if (Math.abs(a)>=Math.abs(b)) epsilon=1e-30*Math.abs(b);
else epsilon=1e-30*Math.abs(a);但正如我所说,这可能导致错误的结果。如果您坚持使用ulp,那么我将使用Min而不是Max。
发布于 2020-08-18 05:43:38
您可以使用来自Apache Commons Math的类Apache Commons Math。示例:
if (Precision.equals(sum, price, 0.009)) {
// arguments are equal or within the range of allowed error (inclusive)
}https://stackoverflow.com/questions/43288079
复制相似问题