Opened 11 years ago

Closed 3 years ago

Last modified 3 years ago

#1042 closed merge (fixed)

Floating point exception

Reported by: dons Owned by:
Priority: normal Milestone: 6.6.1
Component: Compiler Version: 6.6
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: x86
Type of failure: Incorrect result at runtime Test Case:
Blocked By: Blocking:
Related Tickets: #8695 Differential Rev(s):
Wiki Page:

Description

The slightly evil expression:

(-2147483648::Int) `div` (-1::Int)

Can produce floating point exceptions in GHCi:

$ ghci-6.6 
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.6, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Prelude> (-2147483648::Int) `div` (-1::Int)
zsh: floating point exception (core dumped)  ghci-6.6

Compiled:

$ cat A.hs
main = print $ (-2147483648::Int) `div` (-1::Int)

$ ghc A.hs

$ ./a.out 
zsh: floating point exception (core dumped)  ./a.out

Compiled -O:

$ ghc -O -no-recomp A.hs

$ ./a.out               
zsh: floating point exception (core dumped)  ./a.out

In Hugs:

Hugs.Base> (-2147483648::Int) `div` (-1::Int)
Unexpected signal

A C test cases:

$ cat t.c
#include <stdio.h>

int main() {
    printf("%d\n",((int)(-2147483648)) / ((int)(-1)));
    return 0;
}

$ gcc t.c
t.c: In function `main':
t.c:4: warning: this decimal constant is unsigned only in ISO C90
t.c:4: warning: integer overflow in expression

$ ./a.out 
-2147483648

Another:

$ cat t.c
#include <stdio.h>

main () {
    int i = -2147483648;
    int j = -1;
    int k = i / j;
    printf("%d\n", k);
}

$ gcc t.c
t.c: In function `main':
t.c:4: warning: this decimal constant is unsigned only in ISO C90

$ ./a.out 
zsh: floating point exception (core dumped)  ./a.out

What does H98 say about this?

-- Don

Change History (13)

comment:1 Changed 11 years ago by igloo

Milestone: 6.6.1

I can't see anything in Haskell98 about it, but raising ArithException Overflow looks like the right thing to me. This is the only case we need to worry about, right? (for each of the signed types).

Thanks Ian

comment:2 Changed 11 years ago by simonmar

None of the arithmetic operations on Int check for overflow, they all wrap around modulo the size of the Int type, so it seems to me we should be consistent and yield 0 for this case. Haskell 98 says that overflow is implementation-defined, so it's up to us what we do.

Anyway, the place is GHC.Real, in the the Integral instance for Int. Also the various other integral types in GHC.Int need the same treatment.

comment:3 Changed 11 years ago by igloo

minBound seems to be a better answer than 0 to me, but I would prefer an exception to both of them. That way div would always either succeed or raise an exception (div by zero or overflow).

Also, unlike addition overflow (say), we need to check for this happening anyway, so there is no performance advantage to just letting it wrap by itself.

Finally, I would expect that programmers realise that addition, multiplication etc might wrap, but I suspect none have considered that division might.

Thanks Ian

comment:4 Changed 11 years ago by simonmar

Those are certainly reasonable points - I'm happy to raise an exception in this case.

comment:5 Changed 11 years ago by igloo

Owner: set to igloo

comment:6 Changed 11 years ago by igloo

Type: bugmerge

comment:7 Changed 11 years ago by igloo

Resolution: fixed
Status: newclosed

Merged to the 6.6 branch.

comment:8 Changed 9 years ago by simonmar

Operating System: UnknownUnknown/Multiple

comment:9 Changed 4 years ago by Ian Lynagh <igloo@…>

In 90f39e878862a7f0aeb452abf5713f12fddc4d19/ghc:

Add a test for trac #1042

comment:10 Changed 4 years ago by hvr

Type of failure: Incorrect result at runtime

comment:11 Changed 3 years ago by dfeuer

Owner: igloo deleted
Resolution: fixed
Status: closednew

I'm sorry to reopen an 8 year old bug, but I tripped over this today while attempting (unsuccessfully, so far) to write a version of divModInt that plays nice with CSE:

divModInt :: Int -> Int -> (Int, Int)
(I# x) `divModInt` (I# y) = case x `divModInt#` y of
                            (# q, r #) -> (I# q, I# r)

divModInt# :: Int# -> Int# -> (# Int#, Int# #)
x# `divModInt#` y# = case x' `quotRemInt#` y# of
                       (# q, r #) -> (# q +# qadj, r +# radj #)
  where
    (# x', qadj, radj #) = if
      | isTrue# (x# ># 0#) && isTrue# (y# <# 0#) -> (# x# -# 1#, -1#, y# +# 1# #)
      | isTrue# (x# <# 0#) && isTrue# (y# ># 0#) -> (# x# +# 1#, -1#, y# -# 1# #)
      | otherwise                                -> (# x#, 0#, 0# #)

When I test this with

main = print $ divModInt minBound (-1)

I get a floating point exception. GHC.Base.divMod does not trip over this, even though it seems to be doing exactly the same arithmetic. As far as I can tell, this is supposed to be handled by quotRemInt#

comment:12 Changed 3 years ago by dfeuer

Resolution: fixed
Status: newclosed

comment:13 Changed 3 years ago by dfeuer

Never mind. The check was elsewhere. Sorry folks!

Note: See TracTickets for help on using tickets.