{-# LANGUAGE ParallelListComp #-}
module Math.Gamma.Lanczos
( gammaLanczos, lnGammaLanczos
, reflect, reflectC
, reflectLn, reflectLnC
) where
import Data.Complex (Complex, imagPart, realPart)
{-# INLINE gammaLanczos #-}
gammaLanczos :: Floating a => a -> [a] -> a -> a
gammaLanczos _ [] _ = error "gammaLanczos: empty coefficient list"
gammaLanczos g cs zp1
= sqrt (2*pi) * x ** (zp1 - 0.5) * exp (negate x) * a cs z
where
x = zp1 + (g - 0.5)
z = zp1 - 1
{-# INLINE lnGammaLanczos #-}
lnGammaLanczos :: Floating a => a -> [a] -> a -> a
lnGammaLanczos _ [] _ = error "lnGammaLanczos: empty coefficient list"
lnGammaLanczos g cs zp1
= log (sqrt (2*pi)) + log x * (zp1 - 0.5) - x + log (a cs z)
where
x = zp1 + (g - 0.5)
z = zp1 - 1
{-# INLINE a #-}
a :: Fractional t => [t] -> t -> t
a [] _ = error "Math.Gamma.Lanczos.a: empty coefficient list"
a cs z = head cs + sum [c / (z + k) | c <- tail cs | k <- iterate (1+) 1]
fractionalPart :: RealFloat a => a -> a
fractionalPart x = case properFraction x of
(i,f) -> let _ = i :: Int in f
{-# INLINE reflect #-}
reflect :: (RealFloat a, Ord a) => (a -> a) -> a -> a
reflect gamma z
| z > 0.5 = gamma z
| fractionalPart z == 0 = 0
| otherwise = pi / (sin (pi * z) * gamma (1-z))
{-# INLINE reflectC #-}
reflectC :: RealFloat a => (Complex a -> Complex a) -> Complex a -> Complex a
reflectC gamma z
| realPart z > 0.5 = gamma z
| imagPart z == 0
&& fractionalPart (realPart z) == 0
= 0/0
| otherwise = pi / (sin (pi * z) * gamma (1-z))
{-# INLINE reflectLn #-}
reflectLn :: (RealFloat a, Ord a) => (a -> a) -> a -> a
reflectLn lnGamma z
| z > 0.5 = lnGamma z
| fractionalPart z == 0 = log (0/0)
| otherwise = log pi - log (sin (pi * z)) - lnGamma (1-z)
{-# INLINE reflectLnC #-}
reflectLnC :: RealFloat a => (Complex a -> Complex a) -> Complex a -> Complex a
reflectLnC lnGamma z
| realPart z > 0.5 = lnGamma z
| imagPart z == 0
&& fractionalPart (realPart z) == 0
= log (0/0)
| otherwise = log pi - log (sin (pi * z)) - lnGamma (1-z)