如何比较那些双打序列在Java中是否“大致相等”?

时间:2012-02-01 03:49:39

标签: java double approximation

我在java中有一个返回双数的方法,我想比较每次调用方法时返回的每个双数(比如说5次),这样我就可以得出结论返回的数字几乎是一样的每一次。

我该怎么做?

7 个答案:

答案 0 :(得分:33)

public static boolean almostEqual(double a, double b, double eps){
    return Math.abs(a-b)<eps;
}

eps是衡量平等的标准。

答案 1 :(得分:8)

您必须首先确定“几乎相同”的含义。例如,java.lang.Math中有一个名为ulp()的方法,给定一个double,返回该double和next之间的距离;即,该数字与任何其他数字之间的最小可能差异。您可以简单地比较两个双打之间的差异以及调用该方法的结果。

另一方面,也许你想要两个数字在彼此的1%之内。在这种情况下,执行相同的计算,但使用第一个数字乘以0.01而不是ulp()作为最大可接受距离。

答案 2 :(得分:8)

近似相等是根据绝对差异定义的:如果绝对差值不超过某个(可能是小的)数字,那么您可以说您比较的值“足够接近”。

double diff = Math.abs(actual - expected);
if (diff < 1E-7) {
    // Numbers are close enough
}

你必须非常小心,不要混淆“足够接近”的结尾“等于”,因为这两者根本不同:相等是可传递的(即a == b和b == c一起暗示a == c),而“足够接近”不是传递性的。

答案 3 :(得分:4)

这取决于你的意思类似。如果你想比较绝对错误中的两个数字,例如1e-6你可以使用epsilon。如果你想比较两个double而不管比例。例如1.1e-20和1.3e-20不相似,但1.1e20和1.1e20 + 1e5可以比较原始值。

public static void main(String... args) throws IOException {
    test(1.1e-20, 1.3e-20);
    test(1.1e20, 1.1e20 + 1e5);
}

private static void test(double a, double b) {
    System.out.println(a + " and " + b + ", similar= " + similarUnscaled(a, b, 10));
}

public static boolean similarUnscaled(double a, double b, long representationDifference) {
    long a2 = Double.doubleToRawLongBits(a);
    long b2 = Double.doubleToRawLongBits(b);
    // avoid overflow in a2 - b2
    return ((a2 >= 0) == (b2 >= 0)) &&
            Math.abs(a2 - b2) <= representationDifference;
}

打印

1.1E-20 and 1.3E-20, similar= false
1.1E20 and 1.100000000000001E20, similar= true

答案 4 :(得分:2)

您可以使用 Guava DoubleMath#fuzzyEquals方法(自13.0版开始):

public static boolean fuzzyEquals(double a, double b, double tolerance)
  

如果a和b在彼此的容差范围内,则返回true。   从技术上讲,这相当于Math.abs(a - b)&lt; =   公差|| Double.valueOf的(a).equals(Double.valueOf(B))。

     

值得注意的特殊情况包括:

链接到文档:https://google.github.io/guava/releases/17.0/api/docs/com/google/common/math/DoubleMath.html

答案 5 :(得分:1)

两个双打“近似相等”是什么意思?这意味着双打在彼此的容忍范围内。该公差的大小,以及该公差是表示为绝对数还是两个双打的百分比,取决于您的应用。

例如,如果照片查看器上显示的两张照片在屏幕上占据相同的像素数,则它们的宽度大致相同(英寸),因此您的容差将是根据屏幕像素大小计算的绝对数。另一方面,如果两家金融公司的利润相差0.1%左右,那么它们的利润可能“近似相等”。这些只是假设的例子,但关键在于它取决于您的应用程序。

现在进行一些实施。假设您的应用程序需要绝对容差。然后你可以使用

private static final double TOLERANCE = 0.00001;

public static boolean approxEqual(final double d1, final double d2) {
    return Math.abs(d1 - d2) < TOLERANCE;
}

比较两个双打,并使用

approxEqual(d1, d2) && approxEqual(d1, d3) && approxEqual(d1, d4) && approxEqual(d1, d5)

比较五个双打。

答案 6 :(得分:0)

Apache commons-math 库提供了不错的Precision类(请参阅API Docs),该类可以通过不同方式比较双精度:

Precision.equals(a, b, 0.1); // Tell if |a-b| <= 0.1
Precision.equals(a, b, 10); // Tell if a and b are less than 10 Ulps apart
Precision.equalsWithRelativeTolerance(a, b, 0.05); // Tell if a and b are less than 5% apart