1

Everything seemed to be running okay (for several days), but I ran into an issue only once and having a really hard time to reproduce the problem.

"Comparison method violates its general contract!" was thrown and completely caught me off guard. I have the following:

public class CustomComparator implements Comparator<Chromosome> {

public int compare(Chromosome c1, Chromosome c2){

    return c1.compareTo(c2);
}

} 

My Chromosome class:

public class Chromosome implements Comparable<Chromosome>{

private double rank;

//bunch of methods...

@Override public int compareTo(Chromosome c){

    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if (this.getRank() == c.getRank()) //getRank() simply returns a double value 'rank'
        return EQUAL;

    else if (this.getRank() < c.getRank())
            return BEFORE;

    else  //i.e. (this.getRank() > c.getRank())
        return AFTER;   

}

I have an ArrayList and I used both Collections.sort(MyList) and Collections.sort(MyList, Collections.reverseOrder()). They're still working fine up till now. I just ran into that error only once out of 100's of run. Is there something wrong with this implementation?

wFateem
  • 346
  • 1
  • 2
  • 11
  • 1
    Are any of the double values NaN? – Jon Skeet Dec 06 '14 at 13:29
  • Probably result of `0.0/0.0` or something like that. – Gábor Bakos Dec 06 '14 at 13:30
  • 2
    Also your compareTo method could simply be, `return Double.compare(this.rank, c.rank);`. And your custom comparator is useless since its calling `compareTo` on the Chromosome instances itself. – Alexis C. Dec 06 '14 at 13:31
  • Is it possible that rank is NaN? NaN is neither greater than, less than, or equal to NaN. See [the answers to this question](http://stackoverflow.com/questions/1565164/what-is-the-rationale-for-all-comparisons-returning-false-for-ieee754-nan-values) for an explanation. – Mike Samuel Dec 06 '14 at 13:53

2 Answers2

3

Java 7 has changed the behavior of their sorting algorithms a bit. They now throw an Exception if a violation of the general contract for the compareTo method is detected. You can read about that contract's properties for example here.

In general it could be violated for example in case that it would resolve to a < b and b < a. If this was detected before Java 7, it was just silently ignored. Now an Exception will be thrown.

If you want to use the old behaviour, you may use the following:

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

But I don't encourage you to do this. You should just change your implementation to the standard implementation of double comparison via Double.compare(a, b). This implementation correctly deals with infinity and NaN values for doubles.

Furthermore if your Comparator just delegates to the compareTo method, it can be discarded in general.

noone
  • 19,520
  • 5
  • 61
  • 76
  • Thanks. I'll just use Double.compare() instead. I haven' run into the issue again, so it's quite strange. Also, I'm not sure I understand the example you've given which violates the contract. How can I have two double values a and b, such that a < b and at the same time b < a? – wFateem Dec 07 '14 at 16:43
  • 1
    @wFateem It was just an example of how it could be violated. There are actually several other rules that have to be followed. For example the one of symmetry. a == a is supposed to be always true. But the IEEE 754 standard which defines how doubles work, states that Double.NaN should be != Double.NaN, which does violate the rule of symmetry. That's one of the things that Double.compare(...) fixes. – noone Dec 07 '14 at 17:53
  • Thanks a lot for the clarification. Appreciate it – wFateem Dec 08 '14 at 13:24
2

Possibly that one of your parameter might be due to positive or negative infinity i.e. dividing by zero. Also don't rely upon == on double values. You should just use:

return Double.compare(this.getRank(), c.getRank());
SMA
  • 36,381
  • 8
  • 49
  • 73
  • Thanks for the tip on the Double.compare() probably makes more sense to use that instead. It can't be an issue of a division by zero. Rank is only the value returned by a neural network based on pixel values of an image (int between 0 and 255). A sigmoid function is used by the neural network. – wFateem Dec 07 '14 at 16:40
  • Glad it helped. Please close this question by accepting the answer so it can help other's with similar issue. – SMA Dec 07 '14 at 16:41