[GHC] #10378: min/max for Double/Float instances are incorrect

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Blocked By: Test Case: | Related Tickets: Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- This is similar to many other numeric issues around `Double`s and `Float`s. The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell does not satisfy this property. Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments. The following cases demonstrate the issue with `max`, but `min` has the exact same problems. {{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}} It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant: {{{#!hs maxH x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y minH x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}} Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.) On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Description changed by lerkok: Old description:
This is similar to many other numeric issues around `Double`s and `Float`s.
The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell does not satisfy this property.
Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments.
The following cases demonstrate the issue with `max`, but `min` has the exact same problems.
{{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}}
It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant:
{{{#!hs maxH x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y
minH x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}}
Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.)
On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.)
New description: This is similar to many other numeric issues around `Double`s and `Float`s. The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property. Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments. The following cases demonstrate the issue with `max`. Note that `min` has the exact same problems. {{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}} It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant: {{{#!hs maxH x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y minH x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}} Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.) On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.) -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Description changed by lerkok: Old description:
This is similar to many other numeric issues around `Double`s and `Float`s.
The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property.
Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments.
The following cases demonstrate the issue with `max`. Note that `min` has the exact same problems.
{{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}}
It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant:
{{{#!hs maxH x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y
minH x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}}
Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.)
On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.)
New description: This is similar to many other numeric issues around `Double`s and `Float`s. The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property. Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments. The following cases demonstrate the issue with `max`. Note that `min` has the exact same problems. {{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}} It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant: {{{#!hs max x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y min x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}} Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.) On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.) -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Description changed by lerkok: Old description:
This is similar to many other numeric issues around `Double`s and `Float`s.
The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property.
Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments.
The following cases demonstrate the issue with `max`. Note that `min` has the exact same problems.
{{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}}
It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant:
{{{#!hs max x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y
min x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}}
Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.)
On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.)
New description: This is similar to many other numeric issues around `Double`s and `Float`s. The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property. Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments. The following cases demonstrate the issue with `max`. Note that `min` has the exact same problems. {{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}} It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant: {{{#!hs max x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y min x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}} Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.) On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.) -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Comment (by rwbarton): Hi Levent, I think this is a duplicate of #9530, do you agree? There is some discussion there. I do think this is a topic worth discussing but I'm not sure Trac is the best place for it; for starters it's not clear that min on Float/Double *should* be IEEE754-compliant. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Comment (by lerkok): @rwbarton: Ah, thanks for that pointer, I'm not sure if it's a true duplicate (I didn't see a discussion of +0/-0 in there); but the tickets are indeed related. Feel free to close/merge. I definitely agree that we need more discussion on this. Since the other one is closed, perhaps this one can stay. PS. I just found out that the min/max implementation in Intel CPU's actually do not follow the reference implementation I gave in the ticket precisely. I'll put a note in there. Something else to discuss on how to proceed. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Description changed by lerkok: Old description:
This is similar to many other numeric issues around `Double`s and `Float`s.
The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property.
Furthermore, the current definitions are not commutative, when given `NaNs` and `-0` arguments.
The following cases demonstrate the issue with `max`. Note that `min` has the exact same problems.
{{{#!hs Prelude> (0/0) `max` 5 NaN Prelude> 5 `max` (0/0) 5.0 Prelude> isNegativeZero ((-0) `max` 0) False Prelude> isNegativeZero (0 `max` (-0)) True }}}
It wouldn't be hard to fix the definitions appropriately; here are reference implementations that are IEEE754 compliant:
{{{#!hs max x y | isNaN x = y | isNaN y = x | x > y || (x == y && isNegativeZero y) = x | True = y
min x y | isNaN x = y | isNaN y = x | x < y || (x == y && isNegativeZero x) = x | True = y }}}
Note that these reference implementations would be quite expensive if GHC were to use them directly. Luckily, IEEE754 compliant min/max operations are supported by all modern CPUs, so doing the "right" thing here is also the cheaper thing as well. (i.e., it'll even be faster than the current incorrect implementation.)
On platforms that do not have hardware implementations, the above definitions can serve as the correct implementations, albeit they'll be slower. (Embedded devices, perhaps.)
New description: This is similar to many other numeric issues around `Double`s and `Float`s. The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property. Unfortunately, the IEEE-spec isn't exactly clear on how min/max should work around +0/-0. It's deliberately underspecified. Most Intel implementations simply return the second argument in this case. So, the following would be the "reference" implementation, assuming we map to the Intel CPU instructions for floating-point min/max: {{{#!hs max x y | isNaN x = y | isNaN y = x | (x == 0) && (y == 0) = y | x > y = x | True = y min x y | isNaN x = y | isNaN y = x | (x == 0) &&& (y == 0) = y | x < y = x | True = y }}} -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Description changed by lerkok: Old description:
This is similar to many other numeric issues around `Double`s and `Float`s.
The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property.
Unfortunately, the IEEE-spec isn't exactly clear on how min/max should work around +0/-0. It's deliberately underspecified. Most Intel implementations simply return the second argument in this case. So, the following would be the "reference" implementation, assuming we map to the Intel CPU instructions for floating-point min/max:
{{{#!hs max x y | isNaN x = y | isNaN y = x | (x == 0) && (y == 0) = y | x > y = x | True = y
min x y | isNaN x = y | isNaN y = x | (x == 0) &&& (y == 0) = y | x < y = x | True = y }}}
New description: This is similar to many other numeric issues around `Double`s and `Float`s. The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property. Unfortunately, the IEEE-spec isn't exactly clear on how min/max should work around +0/-0. It's deliberately underspecified. Most Intel implementations simply return the second argument in this case. So, the following would be the "reference" implementation, assuming we map to the Intel CPU instructions for floating-point min/max: {{{#!hs max x y | isNaN x = y | isNaN y = x | (x == 0) && (y == 0) = y -- takes care of +/-0 | x > y = x | True = y min x y | isNaN x = y | isNaN y = x | (x == 0) &&& (y == 0) = y -- takes care of +/-0 | x < y = x | True = y }}} -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: high | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Blocked By: | Test Case: Related Tickets: | Blocking: | Differential Revisions: -------------------------------------+------------------------------------- Description changed by lerkok: Old description:
This is similar to many other numeric issues around `Double`s and `Float`s.
The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property.
Unfortunately, the IEEE-spec isn't exactly clear on how min/max should work around +0/-0. It's deliberately underspecified. Most Intel implementations simply return the second argument in this case. So, the following would be the "reference" implementation, assuming we map to the Intel CPU instructions for floating-point min/max:
{{{#!hs max x y | isNaN x = y | isNaN y = x | (x == 0) && (y == 0) = y -- takes care of +/-0 | x > y = x | True = y
min x y | isNaN x = y | isNaN y = x | (x == 0) &&& (y == 0) = y -- takes care of +/-0 | x < y = x | True = y }}}
New description: This is similar to many other numeric issues around `Double`s and `Float`s. The IEEE754 requires `min` and `max` on floats to return the "other" number, if one of the arguments is `NaN`. The default definitions used in Haskell do not satisfy this property. Unfortunately, the IEEE-spec isn't exactly clear on how min/max should work around +0/-0. It's deliberately underspecified. Most Intel implementations simply return the second argument in this case. So, the following would be the "reference" implementation, assuming we map to the Intel CPU instructions for floating-point min/max: {{{#!hs max x y | isNaN x = y | isNaN y = x | (x == 0) && (y == 0) = y -- takes care of +/-0 | x > y = x | True = y min x y | isNaN x = y | isNaN y = x | (x == 0) && (y == 0) = y -- takes care of +/-0 | x < y = x | True = y }}} -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#10378: min/max for Double/Float instances are incorrect -------------------------------------+------------------------------------- Reporter: lerkok | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.10.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Revisions: -------------------------------------+------------------------------------- Changes (by thomie): * priority: high => normal Comment: Please start a discussion about this on libraries@ or glasgow-haskell- users@. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10378#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC