Ошибка Java: "Метод сравнения нарушает свой общий контракт!"
У меня есть этот код:
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 ответа
Вы можете попасть в эту ситуацию, если у вас есть какие-либо значения 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 для вашей пригодности?
Скорее всего, ваша фитнес-функция нарушена одним из двух способов:
- Он не всегда возвращает одно и то же значение при вызове одного и того же объекта.
- Это может вернуть NaNs. Ваш
compareTo()
не транзитивно в присутствии NaN, как объяснил Джон Скит.
Вы можете переписать свою функцию сравнения, используя Double.compare()
:
public int compareTo(Chromosome o) {
return Double.compare(o.fitness(), this.fitness());
}
Это требует меньше кода и заботится о угловых случаях (NaNs, отрицательный ноль и т. Д.). Разумеется, должны ли эти угловые случаи возникать в первую очередь, решать вам и решать.
Вы должны попробовать добавить if (this == o) return 0;
Потому что один и тот же объект должен быть возвращен равным.