{-# LANGUAGE RebindableSyntax #-}
{- |
Generally before using 'quot' and 'rem', think twice.
In most cases 'divMod' and friends are the right choice,
because they fulfill more of the wanted properties.
On some systems 'quot' and 'rem' are more efficient
and if you only use positive numbers, you may be happy with them.
But we cannot warrant the efficiency advantage.

See also:
Daan Leijen: Division and Modulus for Computer Scientists
<http://www.cs.uu.nl/%7Edaan/download/papers/divmodnote-letter.pdf>,
<http://www.haskell.org/pipermail/haskell-cafe/2007-August/030394.html>
-}
module Algebra.RealIntegral (
   C(quot, rem, quotRem),
   ) where

import qualified Algebra.ZeroTestable   as ZeroTestable
import qualified Algebra.IntegralDomain as Integral
import qualified Algebra.Absolute       as Absolute

import Algebra.Absolute (signum, )
import Algebra.IntegralDomain (divMod, )
import Algebra.Ring (one, ) -- fromInteger
import Algebra.Additive (zero, (+), (-), )

import Data.Int  (Int,  Int8,  Int16,  Int32,  Int64,  )
import Data.Word (Word, Word8, Word16, Word32, Word64, )

import NumericPrelude.Base
import qualified Prelude as P
import Prelude (Integer, )


infixl 7 `quot`, `rem`

{- |
Remember that 'divMod' does not specify exactly what @a `quot` b@ should be,
mainly because there is no sensible way to define it in general.
For an instance of @Algebra.RealIntegral.C a@,
it is expected that @a `quot` b@ will round towards 0 and
@a `Prelude.div` b@ will round towards minus infinity.

Minimal definition: nothing required
-}

class (Absolute.C a, ZeroTestable.C a, Ord a, Integral.C a) => C a where
    quot, rem        :: a -> a -> a
    quotRem          :: a -> a -> (a,a)

    {-# INLINE quot #-}
    {-# INLINE rem #-}
    {-# INLINE quotRem #-}
    quot a
a a
b = (a, a) -> a
forall a b. (a, b) -> a
fst (a -> a -> (a, a)
forall a. C a => a -> a -> (a, a)
quotRem a
a a
b)
    rem a
a a
b  = (a, a) -> a
forall a b. (a, b) -> b
snd (a -> a -> (a, a)
forall a. C a => a -> a -> (a, a)
quotRem a
a a
b)
    quotRem a
a a
b = let (a
d,a
m) = a -> a -> (a, a)
forall a. C a => a -> a -> (a, a)
divMod a
a a
b in
                   if (a -> a
forall a. C a => a -> a
signum a
d a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
forall a. C a => a
zero) then
                         (a
da -> a -> a
forall a. C a => a -> a -> a
+a
forall a. C a => a
one,a
ma -> a -> a
forall a. C a => a -> a -> a
-a
b) else (a
d,a
m)


instance C Integer where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Integer -> Integer -> Integer
quot = Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
P.quot
   rem :: Integer -> Integer -> Integer
rem = Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Integer -> Integer -> (Integer, Integer)
quotRem = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Int     where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Int -> Int -> Int
quot = Int -> Int -> Int
forall a. Integral a => a -> a -> a
P.quot
   rem :: Int -> Int -> Int
rem = Int -> Int -> Int
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Int -> Int -> (Int, Int)
quotRem = Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Int8    where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Int8 -> Int8 -> Int8
quot = Int8 -> Int8 -> Int8
forall a. Integral a => a -> a -> a
P.quot
   rem :: Int8 -> Int8 -> Int8
rem = Int8 -> Int8 -> Int8
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Int8 -> Int8 -> (Int8, Int8)
quotRem = Int8 -> Int8 -> (Int8, Int8)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Int16   where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Int16 -> Int16 -> Int16
quot = Int16 -> Int16 -> Int16
forall a. Integral a => a -> a -> a
P.quot
   rem :: Int16 -> Int16 -> Int16
rem = Int16 -> Int16 -> Int16
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Int16 -> Int16 -> (Int16, Int16)
quotRem = Int16 -> Int16 -> (Int16, Int16)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Int32   where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Int32 -> Int32 -> Int32
quot = Int32 -> Int32 -> Int32
forall a. Integral a => a -> a -> a
P.quot
   rem :: Int32 -> Int32 -> Int32
rem = Int32 -> Int32 -> Int32
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Int32 -> Int32 -> (Int32, Int32)
quotRem = Int32 -> Int32 -> (Int32, Int32)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Int64   where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Int64 -> Int64 -> Int64
quot = Int64 -> Int64 -> Int64
forall a. Integral a => a -> a -> a
P.quot
   rem :: Int64 -> Int64 -> Int64
rem = Int64 -> Int64 -> Int64
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Int64 -> Int64 -> (Int64, Int64)
quotRem = Int64 -> Int64 -> (Int64, Int64)
forall a. Integral a => a -> a -> (a, a)
P.quotRem


instance C Word    where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Word -> Word -> Word
quot = Word -> Word -> Word
forall a. Integral a => a -> a -> a
P.quot
   rem :: Word -> Word -> Word
rem = Word -> Word -> Word
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Word -> Word -> (Word, Word)
quotRem = Word -> Word -> (Word, Word)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Word8   where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Word8 -> Word8 -> Word8
quot = Word8 -> Word8 -> Word8
forall a. Integral a => a -> a -> a
P.quot
   rem :: Word8 -> Word8 -> Word8
rem = Word8 -> Word8 -> Word8
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Word8 -> Word8 -> (Word8, Word8)
quotRem = Word8 -> Word8 -> (Word8, Word8)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Word16  where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Word16 -> Word16 -> Word16
quot = Word16 -> Word16 -> Word16
forall a. Integral a => a -> a -> a
P.quot
   rem :: Word16 -> Word16 -> Word16
rem = Word16 -> Word16 -> Word16
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Word16 -> Word16 -> (Word16, Word16)
quotRem = Word16 -> Word16 -> (Word16, Word16)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Word32  where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Word32 -> Word32 -> Word32
quot = Word32 -> Word32 -> Word32
forall a. Integral a => a -> a -> a
P.quot
   rem :: Word32 -> Word32 -> Word32
rem = Word32 -> Word32 -> Word32
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Word32 -> Word32 -> (Word32, Word32)
quotRem = Word32 -> Word32 -> (Word32, Word32)
forall a. Integral a => a -> a -> (a, a)
P.quotRem

instance C Word64  where
   {-# INLINE quot #-}
   {-# INLINE rem #-}
   {-# INLINE quotRem #-}
   quot :: Word64 -> Word64 -> Word64
quot = Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
P.quot
   rem :: Word64 -> Word64 -> Word64
rem = Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
P.rem
   quotRem :: Word64 -> Word64 -> (Word64, Word64)
quotRem = Word64 -> Word64 -> (Word64, Word64)
forall a. Integral a => a -> a -> (a, a)
P.quotRem