Opened 8 years ago

Closed 4 years ago

Last modified 4 years ago

#5683 closed bug (fixed)

bug in signum function

Reported by: tristes_tigres Owned by:
Priority: normal Milestone: 7.6.1
Component: Prelude Version: 7.0.3
Keywords: Cc: anton.nik@…, mihai.maruseac@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Other Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

IEE754 standard states, that every floating point operation involving a NaN should produce NaN. However, in GHC 7.0.3 (in the current Haskell platform) evaluating

signum (0.0/0.0)

produces -1

Change History (14)

comment:1 Changed 8 years ago by tristes_tigres

And
round (0.0/0.0)
produces a very large negative number.

comment:2 Changed 8 years ago by tristes_tigres

Thoughts about the right (meaning, in the spirit of IEEE754) way to fix this:

Operations truncate, round, ceiling and floor on a floating-point type should return floating-point type, not integral. The operation of rounding need not and should not be combined with type conversion.

comment:3 Changed 8 years ago by igloo

difficulty: Unknown
Milestone: 7.6.1

Thanks for the report.

I think we do need truncate et al to be able to return integral types, though: You need to combine them with the type conversion in order to describe what sort of type conversion you want (e.g. should 7.7 be converted to 7 or 8?).

comment:4 Changed 8 years ago by tristes_tigres

I don't quite understand what you're saying.

"(e.g. should 7.7 be converted to 7 or 8?)."

That is determined by the function you're using: round, floor or ceil. In the context of arithmetic operations, which way you round, say, 7.5, is determined by IEEE rounding-mode flags.

I think we do need truncate et al to be able to return integral types, though:

I see two problems with that: a) Handling of special types: Inf, NaN. They are valid floating-point types, raisig exception on rounding them disagrees with what standard says (and the current way they're handled by Prelude is even worse) b) Making output of round into integral will require conversion back to floating-point in some typical floating-point computations. For instance, take computing of a sine. As a first step, argument is reduced to the interval [0, pi/4] (and then rational approximation is used). Reduction involves rounding the floating-point result of the division by pi. There's abslutely no reason to convert it to integral.

(I speak from floating-point standard perspective)

comment:5 Changed 8 years ago by lelf

Cc: anton.nik@… added

comment:6 Changed 7 years ago by mihai.maruseac

Cc: mihai.maruseac@… added

comment:7 Changed 7 years ago by simonmar

Isn't this the same as #3070?

comment:8 Changed 7 years ago by mihai.maruseac

It is.

comment:9 Changed 7 years ago by simonmar

Resolution: duplicate
Status: newclosed

comment:10 Changed 4 years ago by johnw42

Resolution: duplicate
Status: closednew

Re-opening because it's not entirely a duplicate. Bug #3070 is blocked because of some fundamental issues with how Haskell handles floating-point, but I don't believe those issues preclude fixing the signum function to preserve NaN.

comment:11 Changed 4 years ago by johnw42

Aside from preserving NaN, there's also a question of whether -0.0 should be mapped to 0.0 or left alone. IMHO it should be left unchanged because it permits a nice symmetric implementation:

signum x | x > 0     =  1
         | x < 0     = -1
         | otherwise =  x

Aside: there's some good discussion here of why Python has no signum function. I guess that ship has sailed for Haskell, but it makes me inclined to think there's no universally correct definition, which is why I think having a pretty implementation is as good a reason as any to settle on a definition for the edge cases.

comment:12 Changed 4 years ago by rwbarton

Resolution: fixed
Status: newclosed

This was fixed in 7.10.1. signum (-0.0) is -0.0 now as well.

comment:13 in reply to:  12 Changed 4 years ago by tristes_tigres

Replying to rwbarton:

This was fixed in 7.10.1. signum (-0.0) is -0.0 now as well.

Just tried it on haskell.org page

signum(0.0/0.0)

-1.0 :: Fractional a => a

Doesn't look right to me. What version of Haskell web demo is using?

Last edited 4 years ago by tristes_tigres (previous) (diff)

comment:14 Changed 4 years ago by thomie

This was fixed in commit d9a20573f473cc7389004470999b8a318aa6b3f2:

Author: Alexander Berntsen <alexander@plaimi.net>
Date:   Mon Aug 18 21:43:33 2014 -0500

    Make Prelude.signum handle -0.0 correctly (#7858)
    
    Summary:
    Make the `Float` and `Double` implementations of `signum` handle -0.0
    correctly per IEEE-754.
    
    This, together with "Make Prelude.abs handle -0.0 correctly (#7858)",
    fixes Trac #7858.
    
    Depends on D145
    
    Signed-off-by: Alexander Berntsen <alexander@plaimi.net>
    
    Test Plan:
    signum of (-0.0) should be (-0.0) not 0.0.
    
    Test program:
    
      main =
        putStrLn $ p ++ " " ++ n
        where
          f = show . signum
          p = f (-0.0 :: Double)
        n = f (0.0 :: Double)
    
    Reviewers: ekmett, hvr, rwbarton, austin
    
    Reviewed By: austin
    
    Subscribers: phaskell, simonmar, relrod, ezyang, carter
    
    Differential Revision: https://phabricator.haskell.org/D148
    
    GHC Trac Issues: #7858
Note: See TracTickets for help on using tickets.