Ошибка Java: «Метод сравнения нарушает его общий контракт!» - PullRequest
11 голосов
/ 27 февраля 2012

У меня есть этот код:

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, когда объекты равны. Может кто-нибудь объяснить мне эту ошибку?

Ответы [ 3 ]

9 голосов
/ 27 февраля 2012

Вы можете попасть в эту ситуацию, если у вас есть какие-либо значения 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 соответствовали вашей физической форме?

4 голосов
/ 27 февраля 2012

Скорее всего, ваша фитнес-функция нарушена одним из двух способов:

  1. Не всегда возвращает одно и то же значение при вызове одного и того же объекта.
  2. Это может вернуть NaNs. Ваш compareTo() не является переходным в присутствии NaN, как объяснил Джон Скит.

Вы можете переписать функцию сравнения, используя Double.compare():

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

Это требует меньше кода и учитывает угловые случаи (NaNs, отрицательный ноль и т. Д.). Разумеется, должны ли эти угловые дела возникать в первую очередь, решать вам и решать.

0 голосов
/ 27 февраля 2012

Вы должны попытаться добавить if (this == o) return 0;, поскольку один и тот же объект должен быть возвращен равным.

...