我在java中有一个方法,它返回一个双数,我想比较每次调用该方法时(比如5次)返回的每个双数,这样我就可以得出结论,每次返回的数字几乎相同。
我该怎么做?
public static boolean almostEqual(double a, double b, double eps){
return Math.abs(a-b)<eps;
}
其中eps是平等的度量。
您必须首先决定什么是"几乎相同"。例如,java.lang.Math
中有一个名为ulf()的方法,给定一个double,它会返回该double和下一个之间的距离;即该数字与任何其他数字之间的最小可能差异。您可以简单地比较两个替身之间的差异和调用该方法的结果。
另一方面,也许你希望两个数字之间的距离在1%以内。在这种情况下,进行相同的计算,但使用第一个数乘以0.01
而不是ulp()
作为最大可接受距离。
近似等式是根据绝对差来定义的:如果绝对差没有超过某个可能很小的数字,那么你可以说你正在比较的值"足够接近"。
double diff = Math.abs(actual - expected);
if (diff < 1E-7) {
// Numbers are close enough
}
你必须非常小心,不要混淆"足够接近"one_answers"相等",因为两者根本不同:相等是可传递的(即a==b和b==c一起意味着a==c),而"足够靠近"是不可传递的。
这取决于类似的含义。如果你想在绝对误差范围内比较两个数字,例如1e-6,你可以使用ε。如果要比较两个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
您可以使用Guava和DoubleMath#fuzzyEquals
方法(自13.0版本起):
public static boolean fuzzyEquals(double a, double b, double tolerance)
如果a和b在彼此的公差范围内,则返回true。从技术上讲,这相当于Math.abs(a-b)<公差||Double.valueOf(a).等于(Double.valueOf(b)).
值得注意的特殊情况包括:
文档链接:https://google.github.io/guava/releases/17.0/api/docs/com/google/common/math/DoubleMath.html
两个双打"近似相等"意味着什么?这意味着这两个双打在一定的公差范围内。该公差的大小,以及该公差是表示为绝对数还是表示为两倍的百分比,取决于您的应用程序。
例如,如果照片查看器上显示的两张照片在屏幕上占据相同数量的像素,则它们的宽度(以英寸为单位)大致相同,因此您的容差将是基于屏幕像素大小计算的绝对值。另一方面,如果两家金融公司的利润在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)
比较五个替身。
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