Java错误:"比较方法违反其一般约定!"

13
我可以为您翻译。以下是需要翻译的内容:

我有这段代码:

package org.optimization.geneticAlgorithm;
import org.optimization.geneticAlgorithm.selection.Pair;

public abstract class Chromosome implements Comparable<Chromosome> {
    public abstract double fitness();
    public abstract Pair<Chromosome> crossover(Chromosome parent);
    public abstract void mutation();
    public int compareTo(Chromosome o) {
        int rv = 0;
        if (this.fitness() > o.fitness()) {
            rv = -1;
        } else if (this.fitness() < o.fitness()) {
            rv = 1;
        }
        return rv;
    }
}

每次运行这段代码时我都会得到这个错误:

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:835)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:453)
at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:376)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:182)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
at java.util.Arrays.sort(Arrays.java:472)
at java.util.Collections.sort(Collections.java:155)
at org.optimization.geneticAlgorithm.GeneticAlgorithm.nextGeneration(GeneticAlgorithm.java:74)
at org.optimization.geneticAlgorithm.GeneticAlgorithm.execute(GeneticAlgorithm.java:40)
at test.newData.InferenceModel.main(InferenceModel.java:134)

我使用OpenJDK7u3,当对象相等时返回0。有人能解释一下这个错误吗?


2
你的 fitness() 方法是否总是返回相同的值,无论在同一对象上调用多少次?你能与我们分享实现吗? - Tomasz Nurkiewicz
3个回答

9

如果你的数据中存在NaN值,就可能会遇到这种情况:

例如:

public class Test
{
    public static void main(String[] args) {
        double a = Double.NaN;
        double b = Double.NaN;
        double c = 5;

        System.out.println(a < b);
        System.out.println(a > b);
        System.out.println(b < c);
        System.out.println(c < b);
    }
}

所有这些都会打印出 false。因此,你可能会遇到这样的情况,即两个非 NaN 值都被认为“等于” NaN,但其中一个比另一个大。基本上,你应该弄清楚你想如何处理 NaN 值。当然,还要检查一下那是否真的是问题...你真的想要把 NaN 值用于你的适应性吗?

3
您可能不想要NaN值,但需要知道的是,int Double.compare(double, double)可以进行符合比较器合约的比较。根据Javadoc的规定,使用此比较方式时,NaN值将被视为相等且大于所有其他值。 - Louis Wasserman

4

很可能您的适应函数有问题,有两种情况:

  1. 在调用同一对象时,它不总是返回相同的值。
  2. 它可能会返回NaN。如果存在NaN,则您的compareTo()在Jon Skeet所解释的情况下不具有传递性。

您可以使用Double.compare()重写比较函数:

public int compareTo(Chromosome o) {
    return Double.compare(o.fitness(), this.fitness());
}

这需要更少的代码,并处理角落情况(NaNs,负零等)。当然,首先要确定和解决这些角落情况是否应该出现。

1

你应该尝试添加 if (this == o) return 0;,因为必须返回相等的同一个对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接