[GHC] #9530: min / max do not always return a NaN when one of the arguments is NaN

#9530: min / max do not always return a NaN when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Keywords: | Operating System: MacOS X Architecture: Unknown/Multiple | Type of failure: Incorrect Difficulty: Easy (less than 1 | result at runtime hour) | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Revisions: -------------------------------------+------------------------------------- I assume that this is well-known, but it tripped me up: {{{ Prelude> let inf = 1/0 Prelude> let nan = 0/0 Prelude> min nan inf Infinity Prelude> min inf nan NaN Prelude> min 3 nan NaN Prelude> min nan 3 3.0 Prelude> max nan inf NaN Prelude> max inf nan Infinity Prelude> max 3 nan 3.0 Prelude> max nan 3 NaN }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return a NaN when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: Blocking: | Related Tickets: Differential Revisions: | -------------------------------------+------------------------------------- Comment (by jrp): ... also signum NaN returns -1.0, rather than NaN -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return a NaN when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: invalid | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Changes (by carter): * status: new => closed * resolution: => invalid * related: => 9276 * blockedby: => 9276 Comment: thanks for reporting that you found these behaviors confusing, because they are! (though they are totally kosher with respect to the IEEE Floating point semantics, as well as the Ord instance for floating point numbers, so technically not a bug, but rather a distasteful behavior). thus while it IS an unexpected behavior, its not a bug ( try doing `[1.07 :: Float .. 9.9]`in ghci to see something truly bonkers that ), Its worth noting that the ieee standard specifies an even worse behavior for min and max, that when only one arg is NAN, return the *other* (not NAN) argument! (though the historical motivation is a bit suspect.) In fact, i've been working on writing up a proposal to change the semantics of min and max on floating point values! (should happen some time after ICFP is over this week). I spoke with a number of the Julia lang folks about this issue (which was raised with them after I discussed min/max with a member of their community), and I'll likely propose to change the floating point min / max to have the same semantics as their change https://github.com/JuliaLang/julia/issues/7866 their change is: 1) when either argument of min/max is NAN, return NAN 2) Except: a) for min, when either argument is -\infinity, return - \infinity b) for max, when either argument is +\infinity, return +\infinity that said, i'm letting the design / thinking about the implications bake before writing up a proposal that change (though it seems like the most reasonable possible definition given the constraints of Float and Double), because getting the semantics as right as possible matters, and id like to be confident in changing how math works for haskell before committing to the change. I do think that this change in definition will get unanimous support, but i'm trying to also understand *WHAT* else can be fixed up in the same proposal that should be included along with that change. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

thanks for reporting that you found these behaviors confusing, because
(though they are totally kosher with respect to the IEEE Floating point semantics, as well as the Ord instance for floating point numbers, so technically not a bug, but rather a distasteful behavior).
thus while it IS an unexpected behavior, its not a bug ( try doing `[1.07 :: Float .. 9.9]`in ghci to see something truly bonkers that ),
Its worth noting that the ieee standard specifies an even worse behavior for min and max, that when only one arg is NAN, return the *other* (not NAN) argument! (though the historical motivation is a bit suspect.)
In fact, i've been working on writing up a proposal to change the semantics of min and max on floating point values! (should happen some time after ICFP is over this week). I spoke with a number of the Julia lang folks about this issue (which was raised with
#9530: min / max do not always return a NaN when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: invalid | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:2 carter]: they are! them after I discussed min/max with a member of their community), and I'll likely propose to change the floating point min / max to have the same semantics as their change https://github.com/JuliaLang/julia/issues/7866
their change is: 1) when either argument of min/max is NAN, return NAN 2) Except: a) for min, when either argument is -\infinity, return - \infinity b) for max, when either argument is +\infinity, return +\infinity
that said, i'm letting the design / thinking about the implications bake
before writing up a proposal that change (though it seems like the most reasonable possible definition given the constraints of Float and Double), because getting the semantics as right as possible matters, and id like to be confident in changing how math works for haskell before committing to the change.
I do think that this change in definition will get unanimous support,
but i'm trying to also understand *WHAT* else can be fixed up in the same proposal that should be included along with that change. I think it probably makes sense to have multiple sets of operations available: 1. IEEE compliant stuff, whether sane or not. 2. Stuff that's fast in hardware, whether sane or not. 3. Stuff that's sane. Your \pm\infty thing only makes a sort of sense for some NaN situations, I believe. I can buy `max (1/0) (0/0) = Infinity`, for example, but it's hard for me to make sense of `max (1/0) (sqrt (-1))` being anything but NaN. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return a NaN when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: invalid | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by carter): the ieee min/max behavior on nans is bonkers and useless for us. @dfeuer happy to chat about this more via irc or email, but Floats aren't numbers, they just act like they are, but explaining their semantics in more detail and why/when ieee should be ignored or not is too complicated for trac tickets -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return a NaN when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: invalid | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by carter): most of the IEEE operations that have hardware support baked in are pretty reasonable and what ghc already does. min/max is one of the few operations where the ieee spec, the hardware supported spec, and the reasonable semantics specs are not the same. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return a NaN when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: invalid | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by jrp): I don't have a copy of the standard, but http://en.wikipedia.org/wiki/IEEE_754_revision says {{{ min(x,NaN) = min(NaN,x) = x max(x,NaN) = max(NaN,x) = x }}} which is not satisfied here {{{ Prelude> max 3 nan 3.0 Prelude> max nan 3 NaN }}} http://msdn.microsoft.com/en- gb/library/windows/desktop/jj218760(v=vs.85).aspx agrees: {{{ The IEEE-754R specification for floating point min and max operations states that if one of the inputs to min or max is a quiet QNaN value, the result of the operation is the other parameter. }}} It goes on to add a further wrinkle: {{{ A revision of the IEEE-754R specification adopted a different behavior for min and max when one input is a "signaling" SNaN value versus a QNaN value: }}} So far as I can tell, Haskell does not know anything about signalling NaNs, so this is probably not applicable. I'll change the title of the ticket to make the issue clear. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Changes (by jrp): * status: closed => new * resolution: invalid => -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by carter): @jrp, in this case the IEEE standard doesn't make sense to comply with, if you read that julia lang ticket about the min/max behavior, theres an inline email by one of the IEEE spec authors about the motivation for the nan evading behavior. though I do agree from a strict IEEE compliant behavior standpoint, it is nonconforming, this is a very clear example (perhaps the ONLY example) where min/max are better off being implemented in a different way. Haskell has no need for using Nan to pun representing missing data. (see that julia lang thread for a longer discussion on the matter) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by carter): (though if theres a good argument to the contrary, please share! :) ) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by carter): oh, and http://www.wellposed.com/standards-documents- cache/IEEE%20754%202008%20floating%20point%20standard%20fpstandard-2008.pdf is copy of the ieee spec i keep handy :) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments
is NaN
-------------------------------------+-------------------------------------
Reporter: jrp | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Prelude | Version: 7.8.3
Resolution: | Keywords:
Operating System: MacOS X | Architecture: Unknown/Multiple
Type of failure: Incorrect | Difficulty: Easy (less than 1
result at runtime | hour)
Test Case: | Blocked By: 9276
Blocking: | Related Tickets: 9276
Differential Revisions: |
-------------------------------------+-------------------------------------
Comment (by jrp):
Thanks. I'll have a more detailed look. I can't, however, see any good
reason for having min / max asymmetrical in their arguments, whether the
result is to be NaN or the other argument.
The standard seems to agree. It says (at 5.3.1) that
'''''minNum(x, y) is''' the canonicalized number x if x

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by carter): read what I was saying earlier, we agree the current situation is not satisfactory (and I am working on a proposal to make it better). Interesting, the first version of the IEEE standard (the 1985 standard) doesn't seem to mention anything about min/max http://www.wellposed.com/standards-documents-cache/IEEE754-1985.pdf point being, the challenge is to choose a definition that "works the most" subject to floating point being what it is. And the current on e in ghc BASE is certainly confusing and odd, but that a direct consequence of Float/Double min/max using their ORD instance definition of compare to induce the min/max operations. Thus, we need to balance a few tricky concerns (and definitional consistency!) when changin min/max, because if nothing else, the current behavior is exactly that induced by the defintion of compare on floating point. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Comment (by carter): ok, heres a cleaned up version of the 1985 spec http://www.wellposed.com/standards-documents- cache/ieee754-1985-cleanedup.pdf -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:13 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: invalid | Keywords: Operating System: MacOS X | Architecture: Unknown/Multiple Type of failure: Incorrect | Difficulty: Easy (less than 1 result at runtime | hour) Test Case: | Blocked By: 9276 Blocking: | Related Tickets: 9276 Differential Revisions: | -------------------------------------+------------------------------------- Changes (by rwbarton): * status: new => closed * resolution: => invalid Comment: Replying to [comment:3 dfeuer]:
I think it probably makes sense to have multiple sets of operations available:
1. IEEE compliant stuff, whether sane or not.
2. Stuff that's fast in hardware, whether sane or not.
3. Stuff that's sane.
I whole-heartedly agree with this, but, (at most?!) one of these behaviors can be the behavior of the `Ord Double` instance. Any proposed change to that instance needs to be made through the library submissions process, so I'm going to close this ticket as "invalid". This discussion should continue, though! Maybe here, or perhaps on a new wiki page—there are getting to be a number of these tickets on floating-point behavior and it would be good to have all the discussion in one place. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9530: min / max do not always return the other argument when one of the arguments is NaN -------------------------------------+------------------------------------- Reporter: jrp | Owner: Type: bug | Status: closed Priority: normal | Milestone: Component: Prelude | Version: 7.8.3 Resolution: invalid | Keywords: Operating System: MacOS X | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: 9276 | Blocking: Related Tickets: 9276 | Differential Revisions: -------------------------------------+------------------------------------- Comment (by lerkok): I hate to beat a dead-horse; but in the light of the similarly filed ticket: https://ghc.haskell.org/trac/ghc/ticket/10378, I thought I'd put in my feedback. While Carter is right that the being compliant to the IEEE-spec might be useless, it is nonetheless the "spec", and thus we just have to adhere to. I really do want to see Float/Double to mean IEEE-float/double. The hardware implementation in x86 is actually IEEE compliant; just not in the expected way. The newer ticket I linked to has an implementation that is both IEEE-compliant and follows what x86 hardware is doing. (MINPS, MAXPS instructions.) I wholeheartedly agree that we need more discussion on all matters relating to floats. In particular (though not relevant in this case), the proper handling of rounding modes, and additional functionality such as fma. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9530#comment:15 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC