{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ViewPatterns #-} module Numeric.Basics ( -- * Constants pattern M_E, pattern M_LOG2E, pattern M_LOG10E, pattern M_LN2, pattern M_LN10 , pattern M_SQRT2, pattern M_SQRT1_2 , pattern M_PI, pattern M_PI_2, pattern M_PI_3, pattern M_PI_4 , pattern M_1_PI, pattern M_2_PI, pattern M_2_SQRTPI , Epsilon (..), pattern M_EPS -- * Functions , RealExtras (..), RealFloatExtras (..) , negateUnless -- * Exceptions , IterativeMethod, TooManyIterations, tooManyIterations ) where import Data.Int import Data.Word import GHC.Exception import GHC.Stack import Numeric.PrimBytes -- | \( e \) pattern M_E :: (Eq a, Fractional a) => Fractional a => a pattern M_E = 2.718281828459045235360287471352662498 -- | \( \log_2 e \) pattern M_LOG2E :: (Eq a, Fractional a) => Fractional a => a pattern M_LOG2E = 1.442695040888963407359924681001892137 -- | \( \log_{10} e \) pattern M_LOG10E :: (Eq a, Fractional a) => Fractional a => a pattern M_LOG10E = 0.434294481903251827651128918916605082 -- | \( \log_e 2 \) pattern M_LN2 :: (Eq a, Fractional a) => Fractional a => a pattern M_LN2 = 0.693147180559945309417232121458176568 -- | \( \log_e 10 \) pattern M_LN10 :: (Eq a, Fractional a) => Fractional a => a pattern M_LN10 = 2.302585092994045684017991454684364208 -- | \( \sqrt{2} \) pattern M_SQRT2 :: (Eq a, Fractional a) => Fractional a => a pattern M_SQRT2 = 1.414213562373095048801688724209698079 -- | \( \frac{1}{\sqrt{2}} \) pattern M_SQRT1_2 :: (Eq a, Fractional a) => Fractional a => a pattern M_SQRT1_2 = 0.707106781186547524400844362104849039 -- | \( \pi \) pattern M_PI :: (Eq a, Fractional a) => Fractional a => a pattern M_PI = 3.1415926535897932384626433832795028841971 -- | \( \frac{\pi}{2} \) pattern M_PI_2 :: (Eq a, Fractional a) => Fractional a => a pattern M_PI_2 = 1.570796326794896619231321691639751442 -- | \( \frac{\pi}{3} \) pattern M_PI_3 :: (Eq a, Fractional a) => Fractional a => a pattern M_PI_3 = 1.047197551196597746154214461093167628 -- | \( \frac{\pi}{4} \) pattern M_PI_4 :: (Eq a, Fractional a) => Fractional a => a pattern M_PI_4 = 0.785398163397448309615660845819875721 -- | \( \frac{1}{\pi} \) pattern M_1_PI :: (Eq a, Fractional a) => Fractional a => a pattern M_1_PI = 0.318309886183790671537767526745028724 -- | \( \frac{2}{\pi} \) pattern M_2_PI :: (Eq a, Fractional a) => Fractional a => a pattern M_2_PI = 0.636619772367581343075535053490057448 -- | \( \frac{2}{\sqrt{\pi}} \) pattern M_2_SQRTPI :: (Eq a, Fractional a) => Fractional a => a pattern M_2_SQRTPI = 1.128379167095512573896158903121545172 -- | Define a meaningful precision for complex floating-point operations. class (Eq a, Floating a) => Epsilon a where -- | A small positive number that depends on the type of @a@. -- Compare your values to @epsilon@ to tell if they are near zero. epsilon :: a instance Epsilon Double where epsilon = 1e-12 instance Epsilon Float where epsilon = 1e-6 -- | A small positive number that depends on the type of @a@. pattern M_EPS :: Epsilon a => a pattern M_EPS <- ((epsilon ==) -> True) where M_EPS = epsilon -- | Negate if @False@. -- This is a useful alternative to `signum`, -- when @signum 0 == 0@ causing some troubles. negateUnless :: Num t => Bool -> t -> t negateUnless True = id negateUnless False = negate {-# INLINE negateUnless #-} -- | Extra functions for `Real` types. class (Real a, PrimBytes a) => RealExtras a where -- | @copysign x y@ returns a value with the magnitude of x and the sign of y. -- -- NB: in future, this function is to reimplemented using primops -- and should behave the same way as its C analogue. copysign :: a -> a -> a copysign x y | (x >= 0) == (y >= 0) = x | otherwise = negate x {-# INLINE copysign #-} instance RealExtras Int instance RealExtras Int8 instance RealExtras Int16 instance RealExtras Int32 instance RealExtras Int64 instance RealExtras Word instance RealExtras Word8 instance RealExtras Word16 instance RealExtras Word32 instance RealExtras Word64 instance RealExtras Float where copysign = c'copysignf {-# INLINE copysign #-} instance RealExtras Double where copysign = c'copysignd {-# INLINE copysign #-} -- | Extra functions for `RealFrac` types. class (Epsilon a, RealExtras a, RealFloat a) => RealFloatExtras a where -- | \( \sqrt{ x^2 + y^2 } \). -- -- NB: in future, this function is to reimplemented using primops -- and should behave the same way as its C analogue. hypot :: a -> a -> a hypot x y = scaleFloat ea (sqrt (an*an + bn*bn)) where x' = abs x y' = abs y (a,b) = if x' >= y' then (x', y') else (y', x') (_, ea) = decodeFloat a an = scaleFloat (negate ea) a bn = scaleFloat (negate ea) b {-# INLINE hypot #-} -- | Maximum finite number representable by this FP type. maxFinite :: a instance RealFloatExtras Float where hypot = c'hypotf {-# INLINE hypot #-} maxFinite = 3.40282347e+38 {-# INLINE maxFinite #-} instance RealFloatExtras Double where hypot = c'hypotd {-# INLINE hypot #-} maxFinite = 1.7976931348623157e+308 {-# INLINE maxFinite #-} foreign import ccall unsafe "hypot" c'hypotd :: Double -> Double -> Double foreign import ccall unsafe "hypotf" c'hypotf :: Float -> Float -> Float foreign import ccall unsafe "copysign" c'copysignd :: Double -> Double -> Double foreign import ccall unsafe "copysignf" c'copysignf :: Float -> Float -> Float {- | This is just an alias for the `HasCallStack` constraint. It servers two goals: 1. Document functions that use iterative methods and can fail (supposedly in extremely rare cases). 2. Provide a call stack in case of failure. Use `tooManyIterations` function where necessary if you implement an iterative algorithm and annotate your implementation function with `IterativeMethod` constraint. -} type IterativeMethod = HasCallStack -- | Throw a `TooManyIterations` exception. tooManyIterations :: IterativeMethod => String -- ^ Label (e.g. function name) -> a tooManyIterations s = throw TooManyIterations { tmiUserInfo = s , tmiCallStack = callStack } {- | Typically, this exception can occur in an iterative algorithm; when the number of iterations exceeds a pre-defined limit, but the stop condition is not fulfilled. Use the `IterativeMethod` constraint to annotate functions that throw this exception. -} data TooManyIterations = TooManyIterations { tmiUserInfo :: String -- ^ Short description of the error, e.g. a function name. , tmiCallStack :: CallStack -- ^ Function call stack. -- Note, this field is ignored in the `Eq` and `Ord` instances. } -- | Note, this instance ignores `oodCallStack` instance Eq TooManyIterations where (==) a b = tmiUserInfo a == tmiUserInfo b -- | Note, this instance ignores `oodCallStack` instance Ord TooManyIterations where compare a b = compare (tmiUserInfo a) (tmiUserInfo b) instance Show TooManyIterations where showsPrec p e = addLoc errStr where addLoc s = let someE = errorCallWithCallStackException s (tmiCallStack e) errc :: ErrorCall errc = case fromException someE of Nothing -> ErrorCall s Just ec -> ec in showsPrec p errc errStr = unlines [ "An iterative method has exceeded the limit for the iteration number." , "User info: " ++ tmiUserInfo e ] instance Exception TooManyIterations