提问者:小点点

怎样才能摆脱不及物比较器?


我有一个比较器

float d = o1.bar - o2.bar;
if (Math.abs(d) <= 0.001) {
    return 0;
} else {
    return d < 0 ? -1 : 1; // inline Math.copySign
}

本质上,这应该是根据bar属性比较两个Foos,除非值足够接近,在这种情况下,它们应该被声明为相等。(这很重要,因为我在另一处房产上做了另一种分类。)

不过,很明显,这不是一个传递比较器。如果有Foosf1f2f3bar的值分别为1.9992.0002.001,那么根据我的比较器,f1==f2f2==f3f1!=f3

调用的排序(myListofFoo, myFo的比较)给出了一个比较方法违反了它的一般合同!错误很少,但确定。

如何在不生成此错误的情况下将这样的比较器与 Collections.sort(List, Comparator) 一起使用?

或者,有没有什么方法可以存储我的数据,让比较器正常工作?在构造时将每个浮点路由到最近的0.001将是最简单的解决方案,除了Foo.bar字段实际上是基于任意距离度量计算的,所以没那么简单。

实际代码是:

float d = metric.distance(vertex, o1)
        - metric.distance(vertex, o2);
if (Math.abs(d) < threshold) {
    return 0;
} else {
    return d < 0 ? -1 : 1; // inline Math.copySign
}

其中o1o2顶点类Point{浮点x;浮点y;}度量接口距离度量{浮点距离(Point p1, Point p2);}的实例。值得注意的是,即使在标准欧几里得度量上,这也失败了。


共2个答案

匿名用户

恐怕Java7排序实现不会容忍表现出不敏感的Comparator。如果您想使用标准的JavaSE排序API,您对此无能为力。

但是,事实上,在排序中使用阈值比较实际上在数学上是不正确的。

比较浮点值时的问题是,它们通常一开始就不精确,然后计算通常会在结果中引入更小的误差。当两个结果足够接近时,累积误差可能大于两个值之间的差值...这意味着我们无法判断理想数字(没有误差)是小于、等于还是大于每个误差。我们通过使用阈值进行比较,将“接近相等”视为“相等”来处理这个问题。

当我们对值进行排序(即按顺序排列)时,需要以不同的方式处理值中的错误问题。假设

> < li>

我们有两个号码< code>v1 e1和< code>v2 e2,以及

当我们使用阈值比较比较数字时,阈值大于mod(e1)mod(e2)

如果事实证明 v1 和 v2 足够接近 mod(v1 - v2)

因此,如果我们忽略错误并简单地使用精确比较对数字进行排序,那么当我们使用基于阈值的比较时,我们不会以不正确的顺序排列任何一对数字。

现在假设我们有v1±e1v2±e2v3±e3…并且mod(e1)mod(e3)是我们的阈值大:

>

  • 如果我们按照上面的顺序排序(使用精确的比较),我们仍然会以正确的顺序得到数字。

    如果我们使用“与阈值比较”来对值进行排序(排序实现允许这样做!),我们最终可能会得到 v3 ± e3v2 ± e2 和 v1 ± e1 的数字。我们有 {v1 ± e1、v2 ± e2} 和 {v2 ± e2、v3 ± e3} 成对相等,但我们也可能有 {v1 ± e3、v3 ± e3} 错误排序,即使我们使用基于阈值的比较进行比较!

    底线是您应该简单地实现您的< code >比较器(用于排序目的!)来使用精确比较。阈值比较不适用于此上下文。这与< code>sort算法的编码方式无关...

  • 匿名用户

    我猜你实际上想做的是删除重复值(根据你的阈值),然后对其余的进行排序。你为什么不首先根据非四舍五入的值进行自然排序,然后根据你的阈值使用过滤。