packages feed

gamma 0.9.0.2 → 0.10.0.0

raw patch · 13 files changed

+547/−34 lines, 13 filesdep +QuickCheckdep +erfdep +gammadep ~basedep ~continued-fractionssetup-changednew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, erf, gamma, numbers, test-framework, test-framework-quickcheck2

Dependency ranges changed: base, continued-fractions

API changes (from Hackage documentation)

- Math.Factorial: instance Factorial (Complex Double)
- Math.Factorial: instance Factorial (Complex Float)
- Math.Factorial: instance Factorial Double
- Math.Factorial: instance Factorial Float
- Math.Factorial: instance Factorial Integer
- Math.Gamma: instance Gamma (Complex Double)
- Math.Gamma: instance Gamma (Complex Float)
- Math.Gamma: instance Gamma Double
- Math.Gamma: instance Gamma Float
- Math.Gamma: instance IncGamma Double
- Math.Gamma: instance IncGamma Float
+ Math.Factorial: instance Math.Factorial.Factorial (Data.Complex.Complex GHC.Types.Double)
+ Math.Factorial: instance Math.Factorial.Factorial (Data.Complex.Complex GHC.Types.Float)
+ Math.Factorial: instance Math.Factorial.Factorial GHC.Integer.Type.Integer
+ Math.Factorial: instance Math.Factorial.Factorial GHC.Types.Double
+ Math.Factorial: instance Math.Factorial.Factorial GHC.Types.Float
+ Math.Gamma: class Gamma a => GenGamma a
+ Math.Gamma: generalizedGamma :: GenGamma a => Int -> a -> a
+ Math.Gamma: instance Math.Gamma.Gamma (Data.Complex.Complex GHC.Types.Double)
+ Math.Gamma: instance Math.Gamma.Gamma (Data.Complex.Complex GHC.Types.Float)
+ Math.Gamma: instance Math.Gamma.Gamma GHC.Types.Double
+ Math.Gamma: instance Math.Gamma.Gamma GHC.Types.Float
+ Math.Gamma: instance Math.Gamma.GenGamma GHC.Types.Double
+ Math.Gamma: instance Math.Gamma.GenGamma GHC.Types.Float
+ Math.Gamma: instance Math.Gamma.IncGamma GHC.Types.Double
+ Math.Gamma: instance Math.Gamma.IncGamma GHC.Types.Float
+ Math.Gamma: lnGeneralizedGamma :: GenGamma a => Int -> a -> a

Files

+ CHANGES.md view
@@ -0,0 +1,11 @@+0.10.0.0+=====++* Temporarily move project's repository from [mokus0](https://github.com/mokus0/gamma) to+  [rockbmb](https://github.com/rockbmb/gamma2). This was a duplication, not a fork, so+  users can create issues in the latter repository as well.+* Enable Travis CI for the project's new repository.+* Increase lower bound for the Cabal version to be used when compiling this+  project from `>=1.6` to `>=1.10`.+* Change the supported GHC versions from the interval [6.10.4 .. 7.4.1] to+  [8.0.2 .. 8.6.1].
+ README.md view
@@ -0,0 +1,31 @@+Gamma+=========++[![Build Status](https://travis-ci.com/rockbmb/gamma2.svg?branch=master)](https://travis-ci.com/rockbmb/gamma2)++`gamma` is a number theory package written in Haskell that aims to provide its users+with the following functionality:++* A typeclass+  ```haskell+  class Num a => Factorial a+  ```+  that provides a [`factorial`](https://en.wikipedia.org/wiki/Factorial) function.+* A typeclass+  ```haskell+  class (Eq a, Floating a, Factorial a) => Gamma a+  ```+  that provides the functions+  + [`gamma`](https://en.wikipedia.org/wiki/Gamma_function)+  + `lnGamma` (natural logarithm of the gamma function) and+  + `lnFactorial` (natural logarithm of the factorial function).+* A typeclass+  ```haskell+  class Gamma a => IncGamma a+  ```+  for the [incomplete lower and upper gamma functions](https://en.wikipedia.org/wiki/Incomplete_gamma_function).+* A typeclass+  ```haskell+  class Gamma a => GenGamma a+  ```+  to represent the [multivariate gamma function](https://en.wikipedia.org/wiki/Multivariate_gamma_function).
Setup.lhs view
@@ -1,5 +1,6 @@ #!/usr/bin/env runhaskell  > import Distribution.Simple+ > main = defaultMain 
gamma.cabal view
@@ -1,34 +1,33 @@ name:                   gamma-version:                0.9.0.2+version:                0.10.0.0 stability:              provisional -cabal-version:          >= 1.6+cabal-version:          >= 1.10 build-type:             Simple -author:                 James Cook <mokus@deepbondi.net>-maintainer:             James Cook <mokus@deepbondi.net>+author:                 James Cook <mokus ΑΤ deepbondi dοt net>+maintainer:             James Cook <mokus ΑΤ deepbondi dοt net>,+                        Alexandre Rodrigues Baldé <alexandrer_b ΑΤ outlook dοt com> license:                PublicDomain-homepage:               https://github.com/mokus0/gamma+homepage:               https://github.com/rockbmb/gamma2+bug-reports:            https://github.com/rockbmb/gamma2/issues  category:               Math, Numerical synopsis:               Gamma function and related functions.-description:            Approximations of the gamma function, incomplete gamma -                        functions, and factorials.+description:            Approximations of the gamma function, incomplete gamma+                        functions, generalized gamma functions, and factorials. -tested-with:            GHC == 6.10.4,-                        GHC == 6.12.1, GHC == 6.12.3,-                        GHC == 7.0.1, GHC == 7.0.2,-                        GHC == 7.2.1,-                        GHC == 7.4.1-rc1+tested-with:            GHC==8.0.2, GHC==8.2.2, GHC==8.4.3, GHC==8.6.1 -extra-source-files:     extras/*.hs+extra-source-files:     extras/*.hs,+                        CHANGES.md,+                        README.md  source-repository head   type: git-  location: git://github.com/mokus0/gamma.git-+  location: git://github.com/rockbmb/gamma2.git -Library+library   hs-source-dirs:       src   ghc-options:          -Wall   exposed-modules:      Math.Factorial@@ -36,8 +35,29 @@                         Math.Gamma.Incomplete                         Math.Gamma.Stirling                         Math.Gamma.Lanczos-  build-depends:        base >= 3 && <5,-                        continued-fractions >= 0.9.1,+  build-depends:        base >= 4.9 && <5,+                        continued-fractions >= 0.10,                         converge,                         template-haskell,                         vector >= 0.5+  default-language: Haskell2010++test-suite gamma-tests+  ghc-options:          -threaded+  hs-source-dirs:       test-suite+  default-language:     Haskell2010+  ghc-options:          -Wall+  type:                 exitcode-stdio-1.0+  main-is:              Test.hs+  build-depends:+    base >= 4.9 && <5,+    erf,+    gamma,+    numbers,+    QuickCheck >= 2.1.1,+    test-framework,+    test-framework-quickcheck2+  other-modules:+    Math.GammaTests+    Math.IncGammaTests+    Math.Reference
src/Math/Factorial.hs view
@@ -1,9 +1,11 @@ {-# LANGUAGE FlexibleInstances #-}-module Math.Factorial where+module Math.Factorial+    ( Factorial (..)+    ) where -import Data.Complex+import Data.Complex                  (Complex (..)) import qualified Data.Vector.Unboxed as V-import GHC.Float (double2Float)+import GHC.Float                     (double2Float)  -- |Factorial function class Num a => Factorial a where
src/Math/Gamma.hs view
@@ -3,19 +3,20 @@     ( Gamma(..)     , Factorial(..)     , IncGamma(..)+    , GenGamma(..)     ) where  import Math.Gamma.Lanczos import Math.Gamma.Incomplete import Math.Factorial -import Data.Complex-import Data.List (findIndex)-import GHC.Float (float2Double, double2Float)+import Data.Complex                  (Complex (..))+import Data.List                     (findIndex)+import GHC.Float                     (float2Double, double2Float) import qualified Data.Vector.Unboxed as V-import Language.Haskell.TH (litE, Lit(IntegerL))-import Math.ContinuedFraction-import Math.Sequence.Converge+import Language.Haskell.TH           (litE, Lit(IntegerL))+import Math.ContinuedFraction        (modifiedLentz)+import Math.Sequence.Converge        (converge)  -- |Gamma function.  Minimal definition is ether 'gamma' or 'lnGamma'. class (Eq a, Floating a, Factorial a) => Gamma a where@@ -27,11 +28,10 @@         | z == abs z    = exp (lnGamma z)         | otherwise     = pi / (sin (pi * z) * exp (lnGamma (1-z))) -     -- |Natural log of the gamma function     lnGamma :: a -> a     lnGamma z = log (gamma z)-    +     -- |Natural log of the factorial function     lnFactorial :: Integral b => b -> a     lnFactorial n = lnGamma (fromIntegral n+1)@@ -284,4 +284,32 @@         | otherwise =             converge . concat             $ modifiedLentz 1e-30 (qCF s x)++-- |Generalized gamma function (also known as multivariate gamma function).+-- See http://en.wikipedia.org/wiki/Multivariate_gamma_function+-- (Fetched Feb 29, 2012).+class Gamma a => GenGamma a where+    -- |Generalized gamma function.  generalizedGamma p x = (pi ** ((p - 1) / 2)) * gamma x * generalizedGamma (p - 1) (x - 0.5)+    generalizedGamma :: Int -> a -> a+    -- |Natural log of generalizedGamma+    lnGeneralizedGamma :: Int -> a -> a++instance GenGamma Float where+    generalizedGamma   u x = double2Float $ (generalizedGamma   :: Int -> Double -> Double) u (float2Double x)+    lnGeneralizedGamma u x = double2Float $ (lnGeneralizedGamma :: Int -> Double -> Double) u (float2Double x)++instance GenGamma Double where+    generalizedGamma u x+        | u <= 0    = error "generalizedGamma p x: p must be strictly positive."+        | u == 1    = gamma x+        | otherwise = pi ** (0.25 * u' * (u' - 1))+            * product [ gamma (x - 0.5 * fromIntegral j) | j <- [0 .. u - 1]]+        where u' = fromIntegral u++    lnGeneralizedGamma u x+        | u <= 0    = error "lnGeneralizedGamma p x: p must be strictly positive."+        | u == 1    = lnGamma x+        | otherwise = (0.25 * log pi) * (u' * (u' - 1))+            + sum [ lnGamma (x - 0.5 * fromIntegral j) | j <- [0 .. u - 1]]+        where u' = fromIntegral u 
src/Math/Gamma/Incomplete.hs view
@@ -5,9 +5,10 @@     , upperGammaCF, lnUpperGammaConvergents, qCF     ) where -import {-# SOURCE #-}  Math.Gamma-import Math.ContinuedFraction-import Math.Sequence.Converge+import {-# SOURCE #-} Math.Gamma++import Math.ContinuedFraction    (CF, gcf, modifiedLentzWith, sumPartialProducts)+import Math.Sequence.Converge    (converge)  -- |Continued fraction representation of the lower incomplete gamma function. lowerGammaCF :: (Floating a, Ord a) => a -> a -> Math.ContinuedFraction.CF a
src/Math/Gamma/Lanczos.hs view
@@ -14,7 +14,7 @@     , reflectLn, reflectLnC     ) where -import Data.Complex+import Data.Complex (Complex, imagPart, realPart)  -- |Compute Lanczos' approximation to the gamma function, using the specified -- constants.  Valid for Re(x) > 0.5.  Use 'reflect' or 'reflectC' to extend
src/Math/Gamma/Stirling.hs view
@@ -1,7 +1,12 @@ {-# LANGUAGE ParallelListComp #-} -- |Stirling's approximation to the gamma function and utility functions for -- selecting coefficients.-module Math.Gamma.Stirling (lnGammaStirling, cs, s, abs_s, terms) where+module Math.Gamma.Stirling+    ( lnGammaStirling+    , cs+    , s+    , abs_s+    , terms) where  import qualified Data.Vector as V 
+ test-suite/Math/GammaTests.hs view
@@ -0,0 +1,248 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ImplicitParams   #-}+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.GammaTests+    ( eps+    , isSane+    , tests+    , (~=)+    ) where++import qualified Math.Gamma                 as G+import Math.Reference                       (err, lgamma, tgamma)++import Data.Complex                         (Complex (..), conjugate, imagPart,+                                             magnitude, realPart)+import Test.Framework                       (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck                      (Arbitrary, NonNegative (..), Positive (..),+                                             (==>))++gammaSign :: (RealFrac a, Fractional t) => a -> t+gammaSign x+    | x > 0     = 1+    | otherwise = case properFraction x of+        (_, 0)              -> 0/0+        (n, _)  | odd n     ->   1+                | otherwise ->  -1++gammaArg :: RealFrac a => a -> Bool+gammaArg = not . isNaN . gammaSign++eps :: RealFloat a => a+eps = eps'+    where+        eps' = encodeFloat 1 (1 - floatDigits eps')++infix 4 ~=+(~=) :: (Ord a, Num a, ?eps::a, ?mag::t -> a, Num t)+     => t -> t -> Bool+x ~= y+    =  absErr <= ?eps+    || absErr <= ?eps * min (?mag x) (?mag y)+    where absErr = ?mag (x-y)++isSane :: RealFloat a => a -> Bool+isSane x = all (\f -> not (f x)) [isNaN, isInfinite, isDenormalized]++tests :: [Test]+tests =+    [ testGroup "Float"+        [ testGroup "Native"  (realTests G.gamma (G.lnGamma :: Float -> Float))+        , testGroup "Complex" (complexTests G.gamma (G.lnGamma :: Complex Float -> Complex Float))+        ]+    , testGroup "Double"+        [ testGroup "Native"  (realTests    G.gamma (G.lnGamma :: Double -> Double))+        , testGroup "FFI"     (realTests    tgamma lgamma)+        , testGroup "Complex" (complexTests G.gamma (G.lnGamma :: Complex Double -> Complex Double))+        ]+    ]++realTests :: (Arbitrary a, G.Gamma a, Show a, RealFloat a)+          => (a -> a) -> (a -> a) -> [Test]+realTests gamma lnGamma = +    let ?mag = abs+        ?eps = eps+        ?complex = False+     in [ testGroup "gamma"       (realGammaTests    gamma)+        , testGroup "lnGamma"     (realLogGammaTests gamma lnGamma)+        , testGroup "lnFactorial" (logFactorialTests lnGamma G.lnFactorial)+        ]++complexTests :: (Arbitrary a, G.Gamma (Complex a), G.Gamma a, Show a, RealFloat a)+             => (Complex a -> Complex a) -> (Complex a -> Complex a) -> [Test]+complexTests gamma lnGamma = +    let ?mag = magnitude+        ?eps = eps+        ?complex = True+     in [ testGroup "gamma"   (complexGammaTests    gamma)+        , testGroup "lnGamma" (complexLogGammaTests gamma lnGamma)+        , testGroup "lnFactorial" (logFactorialTests lnGamma G.lnFactorial)+        ]++realGammaTests+    :: (Arbitrary a, ?mag::a -> t, ?complex::Bool, Show a, RealFloat a, RealFloat t)+    => (a -> a) -> [Test]+realGammaTests gamma = +    gammaTests gamma +++    [ testProperty "between factorials" $ \(Positive x) -> +        let gam w = fromInteger (product [1..w-1])+            gamma_x = gamma x `asTypeOf` eps+         in x > 2 && isSane gamma_x+            ==> gam (floor x) <= gamma_x && gamma_x <= gam (ceiling x)+    , testProperty "agrees with factorial" $ \(Positive x) ->+        let gam w = fromInteger (product [1..w-1])+            gamma_x = gamma (fromInteger x)+         in isSane gamma_x ==> +            let ?eps = 16*eps in gam x ~= gamma_x+    , testProperty "agrees with C tgamma" $ \x ->+        let a = gamma x+            b = realToFrac (tgamma (realToFrac x))+         in isSane a ==> +            let ?eps = 512*eps in a ~= b+    , testProperty "agrees with reference implementation" $ \x ->+        let a = gamma x+         in isSane a ==> snd (err gamma x) <= 256*eps+    , testProperty "monotone when x>2" $ \(Positive x) ->+        let x' = x * (1 + 256*eps)+            a = gamma x+            b = gamma x'+         in (x > 2) && (x <= x') && all isSane [a,b] ==> a <= b+    , testProperty "domain check" $ \x ->+        let a = gamma x+         in not (isInfinite a) ==>+            isNaN a == not (gammaArg x)+    , testProperty "sign check" $ \x ->+        let a = gamma x; s = gammaSign x+            signum' z@0 | isNegativeZero z  = -1+                        | otherwise         = 1+            signum' z = signum z+         in gammaArg x && not (isInfinite a) ==>+            signum' a == s+    ]+++complexGammaTests+    :: (Arbitrary a1, G.Gamma a1, ?mag::Complex a1 -> a, ?eps::a,+        ?complex::Bool, Show a1, RealFloat a1, RealFloat a)+    => (Complex a1 -> Complex a1) -> [Test]+complexGammaTests gamma = +    gammaTests gamma +++    [ testProperty "conjugate" $ \x -> +        let gam = gamma x+         in isSane (magnitude gam) ==> conjugate gam ~= gamma (conjugate x)+    , testProperty "real argument" $ \(Positive x) ->+        let z = x :+ 0+            gam = G.gamma x+         in isSane gam ==> +            let ?mag = abs; ?eps = 512 * eps+             in gam ~= realPart (gamma z)+    ]++gammaTests+    :: (Arbitrary t2, ?mag::t2 -> a, ?complex::Bool, Show t2,+       RealFloat a, Floating t2)+    => (t2 -> t2) -> [Test]+gammaTests gamma =+    [ testProperty "increment arg" $ \x ->+        let a = gamma x+            b = gamma (x + 1)+            margin  | ?complex  = 32+                    | otherwise = 32+         in all (isSane . ?mag) [a,b,recip a, recip b]+            ==> ?mag (a - b/x) <= margin * (max 2 (1 + recip (?mag x))) * eps * ?mag a+             || ?mag (a*x - b) <= margin * (max 2 (1 +        ?mag x))  * eps * ?mag b+    , testProperty "reflect" $ \x ->+        ?mag x > 0 ==>+        let a = gamma x+            b = gamma (1 - x)+            c = sin (pi * x) / pi+            margin  | ?complex  = 16+                    | otherwise = 256+         in all (isSane . ?mag) [a,b,c]+            -- There may be tighter bounds to be found but I haven't+            -- been able to derive them yet.+            ==> ?mag (a*b*c-1) <= margin * eps * (1 + ?mag c * (1 + ?mag (a+b)))+             || ?mag (a*b*c-1) <= margin * eps * (?mag (a*b) + ?mag (a*c) + ?mag (b*c))+    ]++logGammaTests+    :: (Arbitrary t, ?mag::t -> t1, ?complex::Bool, Show t,+        RealFloat t1, Ord a1, Ord a, Num a1, Num a, Floating t)+    => (t -> t) -> (t -> t) -> (t -> a) -> (t -> a1) -> [Test]+logGammaTests gamma lnGamma real imag =+    [ testProperty "increment arg" $ \x ->+        let gam = lnGamma (x+1)+         in real x > 0 && isSane (?mag gam)+            ==> +            let ?eps = 32 * eps+             in gam - log x ~= lnGamma x+                || gam ~= log x + lnGamma x+    , testProperty "reflect" $ \x ->+        ?mag x > 0 ==>+        let a = lnGamma x+            b = lnGamma (1 - x)+            c = log pi - c';    c' = log (sin (pi * x))+         in all (isSane . ?mag) [a,b,c] +            ==> +            let ?eps = 512 * eps+             in     a + b ~= c+                 || a ~= c - b+                 || b ~= c - a+                 || a - b - c' ~= log pi+    , testProperty "agrees with log . gamma" $ \x ->+        let a = log b'    ; a' = exp b+            b = lnGamma x ; b' = gamma x+            margin  | ?complex   = 1024+                    | otherwise  = 16+         in   (real x > 1 || abs (imag x) > 1)+            && all (isSane . ?mag) [a,b,a',b'] ==>+            let ?eps = margin * eps+             in a ~= b || a' ~= b'+    ]++realLogGammaTests+    :: (Arbitrary a, Show a, RealFloat a)+    => (a -> a) -> (a -> a) -> [Test]+realLogGammaTests gamma lnGamma = +    let ?mag = abs+        ?complex = False+     in logGammaTests gamma lnGamma id (const 0) +++        [ testProperty "between factorials" $ \(Positive x) -> +            let gam w = sum $ map (log.fromInteger) [1 .. w-1]+                gamma_x = lnGamma x `asTypeOf` eps+             in x > 2 && isSane gamma_x+                ==> gam (floor x) <= gamma_x && gamma_x <= gam (ceiling x)+        , let ?eps = 2 * eps+           in testProperty "agrees with C lgamma" $ \(NonNegative x) ->+            let a = lnGamma x+                b = realToFrac (lgamma (realToFrac x))+             in let ?eps = 512 * eps+                 in isSane a ==> a ~= b+        ]++complexLogGammaTests+    :: (Arbitrary a, G.Gamma a, Show a, RealFloat a)+    => (Complex a -> Complex a) -> (Complex a -> Complex a) -> [Test]+complexLogGammaTests gamma lnGamma = +    let ?mag = magnitude+        ?complex = True+     in logGammaTests gamma lnGamma realPart imagPart +++        [ testProperty "real argument" $ \(Positive x) ->+            let z = x :+ 0+                gam = G.lnGamma x+             in isSane gam ==> +                let ?eps = 8 * eps+                 in (gam :+ 0) ~= lnGamma z+        ]++logFactorialTests+    :: (?mag::t -> a, ?eps::a, RealFloat a, Num t1, Num t)+    => (t1 -> t) -> (Integer -> t) -> [Test]+logFactorialTests lnGamma lnFactorial =+    [ testProperty "agrees with lnGamma" $ \x ->+        let gam = lnGamma (fromInteger x + 1)+         in isSane (?mag gam)+            ==> let ?eps = 64*eps in gam ~= lnFactorial x+    ]
+ test-suite/Math/IncGammaTests.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE ImplicitParams #-}+module Math.IncGammaTests+    ( tests+    ) where++import Math.GammaTests                      (eps, isSane, (~=))++import Data.Number.Erf                      (Erf (..))+import Math.Gamma                           (Gamma (..), IncGamma (..))+import Test.Framework                       (Test, testGroup)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Test.QuickCheck                      (Arbitrary, NonNegative (..), Positive (..),+                                             (==>))++tests :: [Test]+tests = +    [ testGroup "incomplete gamma"+        [ testGroup "Float"  (incompleteGammaTests (eps :: Float))+        , testGroup "Double" (incompleteGammaTests (eps :: Double))+        ]+    ]++incompleteGammaTests+    :: (Arbitrary a, Show a, RealFloat a, Erf a, IncGamma a)+    => a -> [Test]+incompleteGammaTests epsi =+    let ?mag = abs+     in [ testProperty "lowerGamma + upperGamma" $ \s (NonNegative x) ->+            let a = lowerGamma s x+                b = upperGamma s x+                c = gamma s+             in all isSane [a,b,c] ==> +                let ?eps = 512 * epsi+                 in  a+b ~= c+                    || a ~= c-b+                    || b ~= c-a+        , testProperty "p + q" $ \s (NonNegative x) ->+            let a = p s x+                b = q s x+             in all isSane [a,b] ==>+                let ?eps = 256 * epsi+                 in  a+b ~= 1+                    || a ~= 1-b+                    || b ~= 1-a+        , testGroup "upperGamma"+            [ testProperty "increment s" $ \s (NonNegative x) ->+                let a = upperGamma (s+1) x+                    b = s * upperGamma s x+                    c = x ** s * exp (-x)+                 in all isSane [a,b,c] ==>+                    let ?eps = 1024*epsi+                     in a ~= b+c || a-b ~= c || a-c ~= b+            , testProperty "x = 0" $ \s ->+                let a = upperGamma s 0+                    b = gamma s+                 in all isSane [a,b] ==>+                    let ?eps = 512*epsi+                     in a ~= b+            , testProperty "s = 1, x > 0" $ \(Positive x) ->+                let ?eps = 256*epsi+                 in x /= 0 ==> upperGamma 1 x ~= exp (-x)+--            , testProperty "s = 1, x < 0" $ \(Positive x) ->+--                let ?eps = 256*eps+--                 in x /= 0 ==> upperGamma 1 (-x) ~= exp x+            , testProperty "s = 0.5" $ \(Positive x) ->+                let ?eps = 128 * epsi+                 in upperGamma 0.5 (x*x) / sqrt pi + erf x ~= 1+            ]+        , testGroup "lnUpperGamma"+            [ testProperty "s = 1, x > 0" $ \(Positive x) ->+                let a = lnUpperGamma 1 x+                 in let ?eps = 1024 * epsi+                     in isSane a ==> a ~= (-x)+--            , testProperty "s = 1, x < 0" $ \(Positive x) ->+--                let a = lnUpperGamma 1 (-x)+--                 in let ?eps = 1024 * eps+--                     in isSane a ==> a ~= x+            , testProperty "agrees with upperGamma" $ \s (NonNegative x) ->+                let a = lnUpperGamma s x;   a' = log b+                    b = upperGamma s x;     b' = exp a+                    +                 in all isSane [a,a',b,b'] ==> +                    let ?eps = 128*epsi+                     in a ~= a' || b ~= b'+            ]+        , testGroup "lowerGamma"+            [ testProperty "increment s" $ \s (NonNegative x) ->+                let a = lowerGamma (s+1) x+                    b = s * lowerGamma s x+                    c = x ** s * exp (-x)+                 in not (s==0 || x==0) && all isSane [a,b,c] ==>+                    let ?eps = 1024*epsi+                     in a ~= b-c || a+c ~= b || b-a ~= c+            , testProperty "s = 0.5" $ \(NonNegative x) ->+                let ?eps = 16 * epsi+                 in lowerGamma 0.5 (x*x) / sqrt pi + erfc x ~= 1+            , testProperty "s = 1, x > 0" $ \(Positive x) ->+                let ?eps = 256*epsi+                 in x /= 0 ==> lowerGamma 1 x + exp (-x) ~= 1+--            , testProperty "s = 1, x < 0" $ \(Positive x) ->+--                let ?eps = 256*eps+--                 in x /= 0 ==> lowerGamma 1 (-x) + exp x ~= 1+            ]+        ]
+ test-suite/Math/Reference.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module Math.Reference+    ( err+    , tgamma+    , lgamma+    ) where++import Data.Number.BigFloat (BigFloat, Prec50)+import Math.Gamma.Lanczos   (gammaLanczos, reflect)++-- type Ref = BigFloat (PrecPlus20 (PrecPlus20 (PrecPlus20 Prec50)))+type Ref = BigFloat Prec50++refGamma' :: Ref -> Ref+refGamma' x+    | x > 0 = gammaLanczos g cs x+    | otherwise = case properFraction x of+        (n,0) -> if n > 0 then fromInteger (product [1..n-1]) else 0/0+        _     -> reflect (gammaLanczos g cs) x++g::Fractional a => a+cs::Fractional a => [a]++-- g = 4*pi+-- cs = [9.99999999999999999999999996859805857094649110255858638007521499626667910350917912841651754219621023562696911332e-1,2.41021935915031575671085869856051212251086781069965411063137445014791649207976600743220302513537180075741255296e5,-9.39683442214927629464202549615391497731809604507151681446997378587954930487740163463037083316646661765306020767e5,1.50949462278130416707216346338262717752378737207648778592042488727849492084941928909939218772224986523524827271e6,-1.29196480388800562971760352435290649542587719650708873592882554634240911710117984734995323885290793478347646330e6,6.36694128920477129400076563202799705143678072113371399208674087118282528558129436201334367030862320422658246991e5,-1.82471418180570786650926611167028035492537813853558673501139223570434908719610942315092027198546110180213204434e5,2.93229025802547026821102620826974735041884874040373833440904730504747656548457832570174326117298554369079127589e4,-2.42104856309484391962703141393650395582185463486998318684467564163688570420245166352198654798010724012815552809e3,8.70263976705814825513391156852897437425645148258979915072545297700880110517285556763650793819190847901635114815e1,-9.90350651051541084034863017450573967496724797720902585856207732922619895739215627256300090899964209233833558059e-1,1.77111462470160503721207454939884167682509869539871034455375282246563600388989404816104050917245493955854296122e-3,-6.07979338168558073081122926060936198873479110416640952420808116982632249326161497364670524879511535821535057852e-8,2.41177003165992726532912316132624759434987463273639173113847102284810676871579183303359325047268888367893750488e-11,-3.29368781819147402947052101243060083111222984364433304208981956498545487091815683441661638260978104468249346673e-11,2.24453115729169763203131076060244943071934132012991691257619864969664661641236008681074860160604017290650304689e-11,-9.42100302390236927123870056289010276539140677886848718235340783874188089528640301130431598050200664465171227938e-12,2.61294791407497062121812006700436259418110616015207527385647574707939568053359405099396866356159720169068766212e-12,-4.32715100268426644428894578150555672315616608786268711314025106092325719775657429204891211631229932892886729036e-13,2.66596243373922858727920730746965698819332806551704556636516706915515953154082281969632365538824477332141826858e-14,1.77321356734488300746927561707710031581163520443393326611478105950839047661826135657152610805311480453596020540e-15]++-- g = 5*pi+-- cs = [9.99999999999999999999999999993886292491620692316160598686599867606051722036264024489964769505713926399764566018e-1,6.26152503787335403652715374769447739961891146555890980978381175134572365593726917595153339118464456879028200299e6,-3.16335440512758530015177280043484225515804122481774619669315038580009080307294118319420059535265919967069772033e7,6.88835095268754493780533335352036097825929449727064875766761598755949365626134351595870710713568770641108217825e7,-8.46956580333456325307500093500724512731750456929320232801425203134598715275876674318720648707327950233819645139e7,6.47329754881842199772339353831484565977006032033099687741144470787747326331686889977791028752629813425598481151e7,-3.19268433191141469791874286821381470267094549847221319695694408120309390209523512867822254931389981528998092501e7,1.02237086392200672155858881540024824965037923176630968557758516768451829832835513494013895382528680690315693015e7,-2.08890272303961042498315400960754400018306410875319695466462560199939031674854106506443962138469812371142769643e6,2.61321424050856457123433663461415238822132698699274898698444195581028556256292204118246298184152640660180308848e5,-1.86315094230899060297422858598853271269991701222133662269812151190073738494135161781746541881517543444088517450e4,6.72898907328811639584664793087658734023965461622305086223114830302184472501053920325357705077659100329375061164e2,-1.00943157793388998698906942778955472820868316720216759533786330365527456664479196396376802036991852763615117162e1,4.38168530207585179518852579327326813565547855423827923455725302731661798688344684949123570662576923314956409652e-2,-2.56700022740805144017893109688146755394089853324102182680986568703519793504112567874052887016745671988158860509e-5,2.36957641603015216306634255574107168474578275256678299025812704092568833214425267053473328220567647312858972842e-10,1.15694083038124833573384461491621092697227999368580657280434988874851263898593841144273580910524072051004097355e-13,-5.65316256384788292348472745512356223934162359491454541731051455366797335011238891664213587003781560857089287039e-14,8.49474213006453212163254972956476450659399535047675685153282680706022067567488560825213520889992328369290274917e-15,2.28070446151983292921304376186430296779950069002580275483997708509382375273278926321059842672372010645544369814e-15,-1.10200839918603550819509828894654530385656333624024070792512173994075523430080371272123208796268388120390605999e-15,1.38549328695392343672202630014049296547598488298392633928436570519822436737509703285623296516943877681573658856e-16]++-- g = 16+-- cs = [1.00000000000000000000000000000197282505854632603079830840695425875357874385280180091442294078665440768378249098e0,8.46526161663305542149634069187867594722046855412304900854881988813185784117115334278649283694595520258911681345e6,-4.36749138271579683480136186837344589623877333072263981316925882855709622493593700542050638104932540688970449938e7,9.74293930563290544819101625509993544487332726502764966578661696058106791782596806612874880755827781636515874517e7,-1.23204021755002536116556671349951637042719838766566833809791162301292663164161640991555755772951701480576547648e8,9.73252768070985015486610374238589008544120710425762737932789956744946587088886115434931192302762714053106117041e7,-4.99300527228931690175325509502458107530242214409813242610195665492694332478957451089840946485109879221508006660e7,1.67717577881504247993599407438579716255280180251024655266088962746483984030648719508692194681618566416623305775e7,-3.63600580914162233698153144687999173036255278366266794893601829961188765108175483037322789095070584870495716554e6,4.90477280895675364498279606024677805104335312501788362116122862426761656206254084389332939810112070827212068184e5,-3.86134008421465254942234421187656226690536946890041785481282535098425957705374976942206419371390945617575261325e4,1.59799318597802486242335864923532052679307039395883719223156368291075399965515365715900128098360767487863914335e3,-2.92431010362234704149212047766530662168493540855402650510149777639810317548261822822398843227566686564791963281e1,1.74363004063413808172424300916410794128403362491029945418010113517139134404174529869116082145355711405933435336e-1,-1.83889135553342355036509760427653033829857278652806446898154652952072080208456364635472214925432683895177618165e-4,7.33270898586375274415891722892287635561670631889884007144730226480410116396830758987236380519411854625863157502e-9,6.45278000390671865545527420895219728252383858385036218254715732532367519947191407848574538847659484635436688368e-14,-6.94479620536106946656438481553865602897856177541063529072614183743481416853611141761279751208940833601449239078e-14,4.05844190171647299618790214616008990498764985510143852349397107297416322977567534872136697380793297187751912405e-14,-1.31733313666599555356105188113267668954033474011729096786502800127065887481914541186166120448932913511034917752e-14,2.41974657267717455470266193816400294930708183176527991681763060922805701926472008462458376871397921380772169745e-15,-2.02601149216618151544716348082831639958354755920147356248364247315675789908515062799667823982813959353893675328e-16]++g = 16+cs = [1.00000000000000000000000000028760575603001265508442130506014379513956597321465491452116725029663713017318281155302254025482646249861597225426258553986702198310282111660814e0,8.46526161663305542149634069187868312963789113165756291473121826624097304045877402442031648610441688439038240651491328941139813852264197305778456591548908224120094894167246e6,-4.36749138271579683480136186837373556118742078558640362066413127517940638355237243621032816244371668677072024055467961309289136667985789351821077916283681043429310492245048e7,9.74293930563290544819101625512895178907295253257275119766847678373728139529380141034950496249773443820391664483106071950636988772945064231618026141173313776653501642702854e7,-1.23204021755002536116556671362722479624891929606934016862583690470559737742517159607918386688863050322288324639470143518965122467234214549961896872832625644312760192739883e8,9.73252768070985015486610377348101550835843155972616405114822066847313715073349332685175985019283585094322001442327102841230844094173203436533130957487267133091342982903057e7,-4.99300527228931690175325556901821725603229843211023737041708258158778148291264448338140176495149974138608744659105384002613928150272910583070070974922893028621993200088839e7,1.67717577881504247993599895442617443938121576155949723063296052767997809323676003179411440697229440626328003480936049898390416473418451439991990895198019408921657042045389e7,-3.63600580914162233698188824414224911677838005543078337270028990910418595747251549012507094099291095605470928507660671913700304145005691137775901293400972065312587564986433e6,4.90477280895675364500197057167325367117745996005366347188604951009746418243949483785855713959732995794028978290947548233313916565466830346275333882723371675976425249785277e5,-3.86134008421465255019809114269109448642105844599649825606338160546076754535370306095846501745502899782090098798450780912185670412952137486962203827925941120665671522549534e4,1.59799318597802488643745988279123446913929676490559975824444279070965368412618612119375002635982295898117052061965727441889307408959072186532547684742798077234919121659107e3,-2.92431010362235278765051929750170216644701333755426298013832714882892025277018457867985013916936895806752284909319872665280990487229040647950671740315052814101554630827301e1,1.74363004063520607047510940102445356013586745700563922221376454404331547889244236047131697225586656833395848432904781434760496518195945993246362481962863428301094957069334e-1,-1.83889135707484897639922506331631327352704695134176610912010000427967001903568852783866323303740089259923460414793348580157969596224404574122968841894479671002508273424642e-4,7.33288074820458553070627189736492168841920567015366487065477349916549899486012064868307264427889502768168730777757015382371906002557890047275383537043961908550989186406985e-9,-8.14003545649332564829862837358721864946644372854188383148183234349174404580929791883572722401611593795796287442225059328665383671935403293667079588128976652734012111434247e-14,2.30444691867487566543942418193243246136284662851351267620236991760404161776920402164496692134690158656181354762481193169147273885408030319356754409112626454347965677288216e-14,-1.60281647995499836731602960261827820681271025273058699260173363290101149359291286878982917703312074881795295123893833653667997796285463313440572145476822619163620650773297e-15,-1.51961151263436286650314929591024470402675431137010398063941973564941174782047280699515350734586316425940330788036418213975493171611105468630277933898275614760821849251065e-16]++foreign import ccall "math.h lgamma" lgamma :: Double -> Double+foreign import ccall "math.h tgamma" tgamma :: Double -> Double++err :: RealFrac a => (a -> a) -> a -> (a,a)+err approxGamma x = (realToFrac absErr, realToFrac relErr)+    where+        x' = realToFrac x+        +        y = realToFrac (approxGamma x)+        y' = refGamma' x'+        absErr = y - y'+        relErr = absErr / max (abs y) (abs y')
+ test-suite/Test.hs view
@@ -0,0 +1,13 @@+#!/usr/bin/env runhaskell+module Main where++import qualified Math.GammaTests (tests)+import qualified Math.IncGammaTests (tests)++import Test.Framework (defaultMain, testGroup)++main :: IO ()+main = defaultMain +    [ testGroup "Math.Gamma"            Math.GammaTests.tests+    , testGroup "Math.Gamma.Incomplete" Math.IncGammaTests.tests+    ]