-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
all: ordering numeric values, including NaNs, and the consequences thereof #59531
Comments
No answers, just some notes. Java implements a class In Rust the trait C++ and Python programmers are best advised to not sort vectors containing NaN values. In Go we have |
A conservative approach is to make the However, I have a feeling that the effect would be that people who want to sort a slice of floating-point numbers would reach for So there is another approach we can take. Don't permit floating-point types for With this approach, the naïve user will use |
In my experience with Rust, the situation I've seen tends to be more like, "the naïve user will use
|
How much would
be helped by a carefully targeted error message? |
@zephyrtronium I'm not sure I entirely understand your comment about narrowing the constraint. To be clear, you could still use the @dr2chase A good error message would help, of course, but my guess is that most people who want to sort floating-point numbers simply don't care about NaN values at all. So it's weird to tell them that the obvious function doesn't work. Especially since we can choose to make it work. |
@ianlancetaylor I think I had the wrong language in mind when I wrote that part. Since |
I always assumed that the use-cases for Sort(slice)
SortFunc(slice, math.Compare) respectively. It provides an opportunity to opt into a different comparison predicate, while preserving existing behavior. The That being said, I agree that Does renaming |
I forgot to mention the delights of signed zeros. Not as problematic as NaNs, but again inconsistent with regard to traditional "less than" vs. total ordering: https://gotipplay.golang.org/p/qd16ohSUz_p
prints
|
One little idea, could be to consider NaNs and signed 0 as subtypes. But that'd be a language change and would be more involved. Essentially, it'd allow types to be further constrainable so that a non-NaN float64 type can be defined and enforced in user code. The mechanism would still be quite similar to what is done today for interface (assertions, assignment). I imagine that it could solve comparison and ordering in one go. (pun half intended) But that's quite involved I think and not sure if that complexity is warranted (maybe it would be fine, needs further investigation about use-cases). |
An update on the current status. We removed We added We added the I don't know whether there is anything else to do here. I think we're an OK place right now, but I'm definitely too close to the problem. |
There are thorny issues around ordering of numerical values, and rather than add to existing conversations I thought it worth pulling them into their own conversation.
The questions here touch on
math.Compare
(issue #56491) as well as the proposedordered
constraint (issue #59488). That said, I feel there are higher level issues around comparison that should be discussed and resolved before making any other changes to the library or language. I also feel thatmath.Compare
should be pulled for now, not released, until these issues are better understood.Go provides less than and less-than-or-equal operators that apply to strings, integers, and scalar numbers. (There is no ordering for complex values.) The proposal to add an
ordered
constraint somewhere is a priori reasonable as it allows one to write comparators, finders, and sorters that apply to all such types.Except they don't, not quite. The problem is IEEE-754 NaNs. It is a peculiarity of IEEE-754 and its implementation in both hardware and most languages that NaNs do not behave like other numbers under comparison. All "less than" and related comparison operations, including "equals", return
false
when comparing NaNs, even when the bit pattern of the operands is identical. This is specified by IEEE-754 and, although odd, provides an easy way to see if a value is a NaN: if it is neither equal nor unequal to itself, it is not a number.This behavior is the key reason why the map
clear
builtin was added: One cannot pull out all the values of a map to clear it as it is never possible to match a NaN key.Similarly, sorting and such will misbehave in the presence of NaNs. This is why
math.Compare
was added, to provide a total ordering on floating point. But of course, thesort
package does not use it, nor could a generic sorter, at least absent a generic compare, which is possibly what should happen instead.Mischievously, this total ordering of NaNs is also defined by IEEE-754 but is not the standard behavior of less than, either as a hardware instruction or in a programming language.
Thus NaNs are ordered but not by the comparison operator. The consequences of this must be clear before defining any ordering constraint.
That is, the addition of an
ordered
constraint to the language, however it is done, bumps up against this conflict. If it is defined, as suggested, to be any type that implements the<
less than operator, any function that uses that constraint may fail unpredictably if a NaN arises, as IEEE-754 demands. On the other hand, if it is instead defined using the total ordering ofmath.Compare
, programs will always work reliably but the<
operator is then not allowed, which is bizarre for a constraint defining an ordering.Neither of these paths is satisfactory. So what should we do? Short answer, I don't know, but we certainly should not change the language or libraries until we have thoroughly thought this through.
I do not, at least at the moment, propose a solution. Instead I am isolating the issue in a discussion to make sure we do the right thing with
ordered
, so we don't end up in a situation like the one for maps where the language had to be changed to make them behave properly.Discuss.
The text was updated successfully, but these errors were encountered: