-0.0 == 0.0, but issorted([0.0, -0.0]) returns false

There is some kind of sorting order between positive and negative zeros of float types:

julia> issorted([-0.0, 0.0])
true

julia> issorted([0.0, -0.0])
false

But this is not observed when those numbers are compared to each other:

julia> -0.0 < 0.0
false

julia> -0.0 > 0.0
false

julia> -0.0 == 0.0
true

I understand the convenience of treating -0.0 and 0.0 as equal, but in that case, should not issorted([0.0, -0.0]) return true?

(Side note: this apparent inconsistency happens with float types, but not with integers because -0 === 0.)

Sorting uses isless by default, not <. The analogue to == is isequal, and that docstring does explicitly mention the distinction between -0.0 and 0.0, which is mandated by IEEE-754 for total ordering. You can input < for IEEE-754 comparisons instead, but that also violates equivalence transitivity for incomparability !lt(x, y) && !lt(y, x) (not equality ==, that’s a different equivalence relation):

julia> issorted([0.0, -0.0], lt=<)
true

Transitivity is critical for sorting because algorithms can avoid redundantly comparing all pairs; comparing A vs B then B vs C should make B vs C unnecessary. The docstring of sort! gives an example of NaN vs 1.0 and NaN vs 2.0 being incomparable under < yet 1.0 < 2.0, and even if we don’t care where NaN goes, we can still get an unacceptable sorting failure:

julia> sort!([2.0, NaN, 1.0], lt=<) |> println
[2.0, NaN, 1.0]
5 Likes

This is contrary to the documentation, so there could be big caveats. < is not a strict weak order, and is explicitly mentioned as not valid for the case of Float64.

4 Likes

Good catch, amended.

2 Likes

I was not aware of the difference between < and isless. This makes it clear. Thank you!

2 Likes