
Great catch! To be IEEE-754 compliant, signum *should* return NaN on NaN.
Here's the new code:
instance Num Float where
signum x | isNegativeZero x = x
| isNaN x = x
| x == 0 = 0
| x > 0.0 = 1
| otherwise = negate 1
abs x | isNegativeZero x = 0
| x >= 0 = x
| otherwise = negate x
Of course, this extra test makes Simon's point even more relevant; i.e.;
these should map to underlying CPU's native signum/abs functions if
available.
-Levent.
On Thu, Apr 11, 2013 at 2:23 AM, Shachaf Ben-Kiki
On Wed, Apr 10, 2013 at 11:24 AM, Levent Erkok
wrote: The current definition of "abs" and "signum" for the types Float/Double is not IEEE-754 compliant. To wit:
Prelude> abs (-0.0::Float) -0.0 Prelude> signum (-0.0::Float) 0.0
The correct result should be the other way around; abs returning 0.0 and signum returning -0.0 when they receive a negative-zero. The same also holds for the type Double.
The issue came up several times in several forums, with general consensus that the behavior should match the IEEE-754 specs. Here're three different discussions on this matter:
http://www.haskell.org/pipermail/libraries/2011-January/015761.html
http://stackoverflow.com/questions/10395761/absolute-value-of-negative-zero-...
http://www.haskell.org/pipermail/haskell-cafe/2013-April/107471.html
Proposed fix: Section 6.4.4 of the report http://www.haskell.org/onlinereport/basic.html#sect6.4 gives "default" definitions for abs/signum; which fails to take into account of negative-zero values for floating-point types. An easy fix would be to
add
to the report a note on the status of negative-zero for Real/Float instances; with individual implementations explicitly checking for negative-0 first. For instance GHC's implementation can be changed as follows:
instance Num Float where signum x | isNegativeZero x = x | x == 0 = 0 | x > 0.0 = 1 | otherwise = negate 1 abs x | isNegativeZero x = 0 | x >= 0 = x | otherwise = negate x
A similar change would need to be done for the "Num Double" instance as well. Of course, implementations can take advantage of the underlying CPU's native floating-point abs/sign functions if available as well, avoiding explicit tests at the Haskell code; based on the underlying platform.
Library guidelines suggest a discussion period of 2 weeks on this issue. I'm hoping that we can resolve the issue in a timely manner, and at least GHC's implementation can match the desired semantics in the next release. If there's consensus at the end of 2-weeks; I'll go ahead and create a corresponding ticket for GHC.
Thanks,
-Levent.
While we're at it: abs NaN is NaN, but signum NaN is currently -1.0. Maybe it should also be NaN?
Shachaf