{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Math.NumberTheory.Euclidean
( Euclidean(..)
, WrappedIntegral(..)
) where
import Prelude hiding (divMod, div, gcd, lcm, mod, quotRem, quot, rem)
import qualified Prelude as P
import GHC.Exts
import GHC.Integer.GMP.Internals
import Numeric.Natural
class (Eq a, Num a) => Euclidean a where
quotRem :: a -> a -> (a, a)
divMod :: a -> a -> (a, a)
quot :: a -> a -> a
quot x y = fst (quotRem x y)
rem :: a -> a -> a
rem x y = snd (quotRem x y)
div :: a -> a -> a
div x y = fst (divMod x y)
mod :: a -> a -> a
mod x y = snd (divMod x y)
gcd :: a -> a -> a
gcd x y = gcd' (abs x) (abs y)
where
gcd' :: a -> a -> a
gcd' a 0 = a
gcd' a b = gcd' b (abs (a `mod` b))
lcm :: a -> a -> a
lcm _ 0 = 0
lcm 0 _ = 0
lcm x y = abs ((x `quot` (gcd x y)) * y)
coprime :: a -> a -> Bool
coprime x y = gcd x y == 1
extendedGCD :: a -> a -> (a, a, a)
extendedGCD a b = (d, x * signum a, y * signum b)
where
(d, x, y) = eGCD 0 1 1 0 (abs a) (abs b)
eGCD !n1 o1 !n2 o2 r s
| s == 0 = (r, o1, o2)
| otherwise = case r `quotRem` s of
(q, t) -> eGCD (o1 - q*n1) n1 (o2 - q*n2) n2 s t
coprimeIntegral :: Integral a => a -> a -> Bool
coprimeIntegral x y = (odd x || odd y) && P.gcd x y == 1
newtype WrappedIntegral a = WrappedIntegral { unWrappedIntegral :: a }
deriving (Eq, Ord, Show, Num, Integral, Real, Enum)
instance Integral a => Euclidean (WrappedIntegral a) where
quotRem = P.quotRem
divMod = P.divMod
quot = P.quot
rem = P.rem
div = P.div
mod = P.mod
gcd = P.gcd
lcm = P.lcm
coprime = coprimeIntegral
instance Euclidean Int where
quotRem = P.quotRem
divMod = P.divMod
quot = P.quot
rem = P.rem
div = P.div
mod = P.mod
gcd (I# x) (I# y) = I# (gcdInt x y)
lcm = P.lcm
coprime = coprimeIntegral
instance Euclidean Word where
quotRem = P.quotRem
divMod = P.divMod
quot = P.quot
rem = P.rem
div = P.div
mod = P.mod
gcd (W# x) (W# y) = W# (gcdWord x y)
lcm = P.lcm
coprime = coprimeIntegral
instance Euclidean Integer where
quotRem = P.quotRem
divMod = P.divMod
quot = P.quot
rem = P.rem
div = P.div
mod = P.mod
gcd = gcdInteger
lcm = lcmInteger
coprime = coprimeIntegral
instance Euclidean Natural where
quotRem = P.quotRem
divMod = P.divMod
quot = P.quot
rem = P.rem
div = P.div
mod = P.mod
gcd = P.gcd
lcm = P.lcm
coprime = coprimeIntegral