如何比较 Java 中的双精度数序列是否全部“近似相等”?

问题描述 投票:0回答:7

我在java中有一个返回双精度数的方法,我想比较每次调用该方法(比如5次)返回的每个双精度数,这样我就可以得出结论,每次返回的数字几乎相同.

我该怎么做?

java double approximation
7个回答
39
投票
public static boolean almostEqual(double a, double b, double eps){
    return Math.abs(a-b)<eps;
}

其中 eps 是平等的衡量标准。


11
投票

您必须首先确定“几乎相同”是什么意思。例如,

java.lang.Math
中有一个名为 ulp() 的方法,给定一个双精度值,返回该双精度值与下一个双精度值之间的距离;即该数字与任何其他数字之间可能的最小差异。您可以简单地比较两个双精度值之间的差异以及调用该方法的结果。

另一方面,也许您希望两个数字的误差在 1% 以内。在这种情况下,请执行相同的计算,但使用第一个数字乘以

0.01
而不是
ulp()
作为最大可接受距离。


8
投票

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

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

您必须非常小心,不要混淆“足够接近”和“等于”,因为两者本质上是不同的:相等是传递的(即a==b和b==c在一起意味着a==c),而“足够接近”不是传递性的。


5
投票

这取决于你所说的相似是什么意思。如果您想比较绝对误差范围内的两个数字,例如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
投票

您可以使用Guava

DoubleMath#fuzzyEquals
方法(从13.0版本开始):

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

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

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

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


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)

比较五个双打。


1
投票

Apache commons-math库提供了很好的Precision

类(请参阅
API文档),它可以以不同的方式比较双精度数:

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
    
© www.soinside.com 2019 - 2024. All rights reserved.