{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# OPTIONS_GHC -Wall #-}
module NumHask.Algebra.Field
( Semifield
, Field
, ExpField(..)
, QuotientField(..)
, UpperBoundedField(..)
, LowerBoundedField(..)
, BoundedField
, TrigField(..)
) where
import Data.Complex (Complex(..))
import NumHask.Algebra.Additive
import NumHask.Algebra.Multiplicative
import NumHask.Algebra.Ring
import NumHask.Algebra.Integral
import Data.Bool (bool)
import Prelude (Double, Float, Integer, (||))
import qualified Prelude as P
class (MultiplicativeInvertible a, MultiplicativeGroup a, Semiring a) =>
Semifield a
instance Semifield Double
instance Semifield Float
instance (Semifield a, AdditiveGroup a) => Semifield (Complex a)
class (AdditiveGroup a, MultiplicativeGroup a, Ring a) =>
Field a
instance Field Double
instance Field Float
instance (Field a) => Field (Complex a)
class (Field a) =>
ExpField a where
exp :: a -> a
log :: a -> a
logBase :: a -> a -> a
logBase a b = log b / log a
(**) :: a -> a -> a
(**) a b = exp (log a * b)
sqrt :: a -> a
sqrt a = a ** (one / (one + one))
instance ExpField Double where
exp = P.exp
log = P.log
(**) = (P.**)
instance ExpField Float where
exp = P.exp
log = P.log
(**) = (P.**)
instance (P.Ord a, TrigField a, ExpField a) => ExpField (Complex a) where
exp (rx :+ ix) = exp rx * cos ix :+ exp rx * sin ix
log (rx :+ ix) = log (sqrt (rx * rx + ix * ix)) :+ atan2 ix rx
where
atan2 y x
| x P.> zero = atan (y / x)
| x P.== zero P.&& y P.> zero = pi / (one + one)
| x P.< one P.&& y P.> one = pi + atan (y / x)
| (x P.<= zero P.&& y P.< zero) || (x P.< zero) =
negate (atan2 (negate y) x)
| y P.== zero = pi
| x P.== zero P.&& y P.== zero = y
| P.otherwise = x + y
class (P.Ord a, Field a, P.Eq b, Integral b, AdditiveGroup b, MultiplicativeUnital b) =>
QuotientField a b where
properFraction :: a -> (b, a)
round :: a -> b
round x = case properFraction x of
(n,r) -> let
m = bool (n+one) (n-one) (r P.< zero)
half_down = abs' r - (one/(one+one))
abs' a
| a P.< zero = negate a
| P.otherwise = a
in
case P.compare half_down zero of
P.LT -> n
P.EQ -> bool m n (even n)
P.GT -> m
ceiling :: a -> b
ceiling x = bool n (n+one) (r P.> zero)
where (n,r) = properFraction x
floor :: a -> b
floor x = bool n (n-one) (r P.< zero)
where (n,r) = properFraction x
instance QuotientField Float Integer where
properFraction = P.properFraction
instance QuotientField Double Integer where
properFraction = P.properFraction
class (Semifield a) =>
UpperBoundedField a where
infinity :: a
infinity = one / zero
nan :: a
nan = zero / zero
instance UpperBoundedField Float
instance UpperBoundedField Double
class (Field a) =>
LowerBoundedField a where
negInfinity :: a
negInfinity = negate (one / zero)
instance LowerBoundedField Float
instance LowerBoundedField Double
instance (AdditiveGroup a, UpperBoundedField a) =>
UpperBoundedField (Complex a)
class (UpperBoundedField a, LowerBoundedField a) => BoundedField a
instance (UpperBoundedField a, LowerBoundedField a) => BoundedField a
class (Field a) =>
TrigField a where
pi :: a
sin :: a -> a
cos :: a -> a
tan :: a -> a
tan x = sin x / cos x
asin :: a -> a
acos :: a -> a
atan :: a -> a
sinh :: a -> a
cosh :: a -> a
tanh :: a -> a
tanh x = sinh x / cosh x
asinh :: a -> a
acosh :: a -> a
atanh :: a -> a
instance TrigField Double where
pi = P.pi
sin = P.sin
cos = P.cos
asin = P.asin
acos = P.acos
atan = P.atan
sinh = P.sinh
cosh = P.cosh
asinh = P.sinh
acosh = P.acosh
atanh = P.atanh
instance TrigField Float where
pi = P.pi
sin = P.sin
cos = P.cos
asin = P.asin
acos = P.acos
atan = P.atan
sinh = P.sinh
cosh = P.cosh
asinh = P.sinh
acosh = P.acosh
atanh = P.atanh