Fix negation of `divMod`/`quotRem` results (fixes #8726)
authorHerbert Valerio Riedel <hvr@gnu.org>
Sun, 2 Feb 2014 11:18:20 +0000 (12:18 +0100)
committerHerbert Valerio Riedel <hvr@gnu.org>
Sun, 2 Feb 2014 11:49:58 +0000 (12:49 +0100)
High-level pseudo code of what the code was supposed to implement:

    quotRem' :: Integer -> Integer -> (Integer,Integer)
    quotRem' a b@(S# _)
      | b < 0     = negFst . uncurry quotRem' . negSnd $ (a,b)
      | otherwise = quotRemUI a (fromIntegral (abs b))

    divMod' :: Integer -> Integer -> (Integer,Integer)
    divMod' a b@(S# _)
      | b < 0      = negSnd . uncurry divMod' . negBoth $ (a,b)
      | otherwise  = divModUI a (fromIntegral b)

    negFst  (q,r) = (-q,r)
    negSnd  (q,r) = ( q,-r)
    negBoth (q,r) = (-q,-r)

    -- quotRemUI and divModUI represent GMP's `mpz_{f,t}div_qr_ui()`
    quotRemUI, divModUI :: Integer -> Word -> (Integer,Integer)

Signed-off-by: Herbert Valerio Riedel <hvr@gnu.org>
GHC/Integer/Type.lhs

index 8596562..3fb2ae6 100644 (file)
@@ -296,9 +296,9 @@ quotRemInteger (S# i) (S# j) = case quotRemInt# i j of
 #if SIZEOF_HSWORD == SIZEOF_LONG
 quotRemInteger (J# s1 d1) (S# b) | isTrue# (b <# 0#)
   = case quotRemIntegerWord# s1 d1 (int2Word# (negateInt# b)) of
-          (# q, r #) -> let !q' = mpzToInteger(mpzNeg q)
-                            !r' = mpzToInteger(mpzNeg r)
-                        in (# q', r' #)
+          (# q, r #) -> let !q' = mpzToInteger (mpzNeg q)
+                            !r' = mpzToInteger r
+                        in (# q', r' #) -- see also Trac #8726
 quotRemInteger (J# s1 d1) (S# b)
   = mpzToInteger2 (quotRemIntegerWord# s1 d1 (int2Word# b))
 #else
@@ -322,9 +322,9 @@ divModInteger (S# i) (S# j) = (# S# d, S# m #)
 #if SIZEOF_HSWORD == SIZEOF_LONG
 divModInteger (J# s1 d1) (S# b) | isTrue# (b <# 0#)
   = case divModIntegerWord# (negateInt# s1) d1 (int2Word# (negateInt# b)) of
-          (# q, r #) -> let !q' = mpzToInteger (mpzNeg q)
-                            !r' = mpzToInteger r
-                        in (# q', r' #)
+          (# q, r #) -> let !q' = mpzToInteger q
+                            !r' = mpzToInteger (mpzNeg r)
+                        in (# q', r' #) -- see also Trac #8726
 divModInteger (J# s1 d1) (S# b)
   = mpzToInteger2(divModIntegerWord# s1 d1 (int2Word# b))
 #else
@@ -386,7 +386,7 @@ modInteger (S# a) (S# b) = S# (modInt# a b)
 modInteger ia@(S# _) ib@(J# _ _) = modInteger (toBig ia) ib
 #if SIZEOF_HSWORD == SIZEOF_LONG
 modInteger (J# sa a) (S# b) | isTrue# (b <# 0#)
-  = mpzToInteger (mpzNeg (remIntegerWord# (negateInt# sa) a (int2Word# (negateInt# b))))
+  = mpzToInteger (mpzNeg (modIntegerWord# (negateInt# sa) a (int2Word# (negateInt# b))))
 modInteger (J# sa a) (S# b)
   = mpzToInteger (modIntegerWord# sa a (int2Word# b))
 #else