如何以 epsilon 精度检查 a ≤ b

How to check if a ≤ b with an epsilon precision

所以我有两个双打,ab,我需要检查 a ≤ b 是否具有给定 epsilon 的精度。

所以要检查 a == b 我是否需要这样做(ab 是双打,EPSILON 是最后的双打,在我的例子中是 0.001):

Math.abs(a - b) < EPSILON

我对自己问题的回答是:

a < EPSILON + b

我的问题是,如果精度为epsilon,那么最终结果中just less than和less than or equal的区别是什么,也许有人有更好的办法要写吗?

你不想写,a < EPSILON+b,因为如果 b 很大,那么你可能有 b == EPSILON+b,然后 a < EPSILON+b 会失败,如果 ab 完全相等。

(a-b) < EPSILON 有效。

比较具有“epsilon 精度”的数字时,如果数字在 EPSILON 内,则认为它们相同,因此“a < b,具有 epsilon 精度”实际上是:

(a-b) <= -EPSILON

能用BigDecimal就用,否则:

/**
  *@param precision number of decimal digits
  */
public static boolean areEqualDouble(double a, double b, int precision) {
   return Math.abs(a - b) <= Math.pow(10, -precision);
}

更新: 这个 post 是错误的,请看评论。 @matttimmens 的回答似乎是合法的。 (我仍然需要检查极端情况)

UPDATE 2 我检查并学习了。我以为我会找到像整数这样的极端情况。在 Java 中,(Integer.MIN_VALUE == ((-Integer.MIN_VALUE))) 为真。这是因为整数(如:非十进制、非浮点数)具有不对称范围:

  • 第一个正数是0,第一个负数是-1,因此
  • 字节:MAX_VALUE是127,而MIN_VALUE是-128,所以MAX_VALUE != -MIN_VALUEMIN_VALUE != MAX_VALUE
  • 也适用于 short、int、long

这与静默整数溢出混合在一起,在极端角落工作时会产生问题,尤其是差一问题:

    final int a = Integer.MIN_VALUE;
    final int b = Integer.MAX_VALUE;
    final int eps = 1;
    System.out.println("a-b = " + (a - b));
    System.out.println((a - b) < eps);

a-b 结果为 1,而 1 < eps 为假,尽管我们清楚地看到 a 比 b 小很多。 这是算法在 整数 上失败的一种极端情况。注意:OP 大约是 doubles.

然而,Java 中的浮点数(float,double),或者更确切地说,operations 中的浮点数,补偿,并且不允许发生溢出:

  • (Double.MAX_VALUE + 1) == Double.MAX_VALUE 成立
  • (Double.MAX_VALUE + Double.MAX_VALUE) == Double.POSITIVE_INFINITY 成立
  • (-Double.MAX_VALUE + -Double.MAX_VALUE) == Double.NEGATIVE_INFINITY 成立

所以之前,对于整数,+1 或 -1 静默整数溢出会导致问题。 因此,当将 +1(或 -1 或 any 小数)添加到非常大的双精度变量时,更改会因舍入而丢失。因此,极端情况在这里不起作用,@matttimmens 的解决方案 (a-b)<e 与浮点变量最接近事实,四舍五入。

我老了,错了post:

为了反击@matttimmens 的回复,运行 该代码:

    final double a = Double.MIN_VALUE;
    final double b = Double.MIN_VALUE + 0;
    final double c = Double.MIN_VALUE + 10;
    final double e = 0.001;
    System.out.println("Matches 1: " + ((a - b) < e));
    System.out.println("Matches 2: " + ((b - a) < e));
    System.out.println("Matches 3: " + ((a - c) < e));
    System.out.println("Matches 4: " + ((c - a) < e));

第 3 场给出了错误的结果,因此他的答案是错误的。

有趣的是,他想过改变大数字,却对非常小的数字置之不理。