| 1 | ;; Gamma functions |
|---|
| 2 | ;; Liam Healy, Thu Apr 27 2006 - 22:06 |
|---|
| 3 | ;; Time-stamp: <2008-03-27 21:29:36EDT gamma.lisp> |
|---|
| 4 | ;; $Id$ |
|---|
| 5 | |
|---|
| 6 | (in-package :gsl) |
|---|
| 7 | |
|---|
| 8 | ;;; Need to handle incoming gsl-complex numbers correctly for log-gamma-complex. |
|---|
| 9 | ;;; Should functions returning sf-result and something else return the |
|---|
| 10 | ;;; error at the end? |
|---|
| 11 | |
|---|
| 12 | ;;;;**************************************************************************** |
|---|
| 13 | ;;;; Gamma functions |
|---|
| 14 | ;;;;**************************************************************************** |
|---|
| 15 | |
|---|
| 16 | (defconstant +gamma-xmax+ 171.0d0) |
|---|
| 17 | |
|---|
| 18 | (defmfun gamma (x) |
|---|
| 19 | "gsl_sf_gamma_e" ((x :double) (ret sf-result)) |
|---|
| 20 | :documentation ; FDL |
|---|
| 21 | "The Gamma function Gamma(x), subject to x |
|---|
| 22 | not being a negative integer. The function is computed using the real |
|---|
| 23 | Lanczos method. The maximum value of x such that |
|---|
| 24 | Gamma(x) is not considered an overflow is given by +gamma-xmax+.") |
|---|
| 25 | |
|---|
| 26 | (defmfun log-gamma (x) |
|---|
| 27 | "gsl_sf_lngamma_e" ((x :double) (ret sf-result)) |
|---|
| 28 | :documentation ; FDL |
|---|
| 29 | "The logarithm of the Gamma function, |
|---|
| 30 | log(Gamma(x)), subject to x not a being negative |
|---|
| 31 | integer. For x<0 the real part of log(Gamma(x)) is |
|---|
| 32 | returned, which is equivalent to log(|Gamma(x)|). The function |
|---|
| 33 | is computed using the real Lanczos method.") |
|---|
| 34 | |
|---|
| 35 | (defmfun log-gamma-sign (x) |
|---|
| 36 | "gsl_sf_lngamma_sgn_e" ((x :double) (ret sf-result) (sign :double)) |
|---|
| 37 | :return ((val ret) (dcref sign) (err ret)) |
|---|
| 38 | :documentation ; FDL |
|---|
| 39 | "Compute the sign of the gamma function and the logarithm of |
|---|
| 40 | its magnitude, subject to x not being a negative integer. The |
|---|
| 41 | function is computed using the real Lanczos method. The value of the |
|---|
| 42 | gamma function can be reconstructed using the relation Gamma(x) = |
|---|
| 43 | sgn * exp(resultlg)}.") |
|---|
| 44 | |
|---|
| 45 | (defmfun gamma* (x) |
|---|
| 46 | "gsl_sf_gammastar_e" ((x :double) (ret sf-result)) |
|---|
| 47 | :documentation ; FDL |
|---|
| 48 | "The regulated Gamma Function Gamma^*(x) |
|---|
| 49 | for x > 0, given by |
|---|
| 50 | Gamma^*(x) = Gamma(x)/(sqrt{2\pi} x^{(x-1/2)} \exp(-x)) |
|---|
| 51 | = (1 + {1 \over 12x} + ...) |
|---|
| 52 | for x to infinity.") |
|---|
| 53 | |
|---|
| 54 | (defmfun 1/gamma (x) |
|---|
| 55 | "gsl_sf_gammainv_e" ((x :double) (ret sf-result)) |
|---|
| 56 | :documentation ; FDL |
|---|
| 57 | "The reciprocal of the gamma function, |
|---|
| 58 | 1/\Gamma(x) using the real Lanczos method.") |
|---|
| 59 | |
|---|
| 60 | (defmfun log-gamma-complex (z) |
|---|
| 61 | "gsl_sf_lngamma_complex_e" |
|---|
| 62 | (((realpart z) :double) ((imagpart z) :double) |
|---|
| 63 | (lnr sf-result) (arg sf-result)) |
|---|
| 64 | :documentation ; FDL |
|---|
| 65 | "Compute log(Gamma(z)) for complex z=z_r+i z_i |
|---|
| 66 | and z not a negative integer, using the complex Lanczos |
|---|
| 67 | method. The returned parameters are lnr = log|\Gamma(z)| and |
|---|
| 68 | arg = arg(Gamma(z)) in (-pi,pi]. Note that the phase |
|---|
| 69 | part (arg) is not well-determined when |z| is very large, |
|---|
| 70 | due to inevitable roundoff in restricting to (-\pi,\pi]. This |
|---|
| 71 | will result in a :ELOSS error when it occurs. The absolute |
|---|
| 72 | value part (lnr), however, never suffers from loss of precision." |
|---|
| 73 | :return |
|---|
| 74 | ((val lnr) (val arg) (err lnr) (err arg))) |
|---|
| 75 | |
|---|
| 76 | (defmfun taylor-coefficient (n x) |
|---|
| 77 | "gsl_sf_taylorcoeff_e" ((n :int) (x :double) (ret sf-result)) |
|---|
| 78 | :documentation ; FDL |
|---|
| 79 | "Compute the Taylor coefficient x^n / n! for x >= 0, n >= 0.") |
|---|
| 80 | |
|---|
| 81 | (defmfun factorial (n) |
|---|
| 82 | "gsl_sf_fact_e" ((n size) (ret sf-result)) |
|---|
| 83 | :documentation ; FDL |
|---|
| 84 | "The factorial n!, related to the Gamma function by n! = \Gamma(n+1).") |
|---|
| 85 | |
|---|
| 86 | (defmfun double-factorial (n) |
|---|
| 87 | "gsl_sf_doublefact_e" ((n size) (ret sf-result)) |
|---|
| 88 | :documentation ; FDL |
|---|
| 89 | "The double factorial n!! = n(n-2)(n-4) \dots.") |
|---|
| 90 | |
|---|
| 91 | (defmfun log-factorial (n) |
|---|
| 92 | "gsl_sf_lnfact_e" ((n size) (ret sf-result)) |
|---|
| 93 | :documentation ; FDL |
|---|
| 94 | "The logarithm of the factorial of n, log(n!). |
|---|
| 95 | The algorithm is faster than computing |
|---|
| 96 | ln(Gamma(n+1)) via #'log-gamma for n < 170, but defers for larger n.") |
|---|
| 97 | |
|---|
| 98 | (defmfun log-double-factorial (n) |
|---|
| 99 | "gsl_sf_lndoublefact_e" ((n size) (ret sf-result)) |
|---|
| 100 | :documentation ; FDL |
|---|
| 101 | "Compute the logarithm of the double factorial of n, log(n!!).") |
|---|
| 102 | |
|---|
| 103 | (defmfun choose (n m) |
|---|
| 104 | "gsl_sf_choose_e" ((n size) (m size) (ret sf-result)) |
|---|
| 105 | :documentation ; FDL |
|---|
| 106 | "The combinatorial factor (n choose m) = n!/(m!(n-m)!).") |
|---|
| 107 | |
|---|
| 108 | (defmfun log-choose (n m) |
|---|
| 109 | "gsl_sf_lnchoose_e" ((n size) (m size) (ret sf-result)) |
|---|
| 110 | :documentation ; FDL |
|---|
| 111 | "The logarithm of (n choose m). This is |
|---|
| 112 | equivalent to the sum log(n!) - log(m!) - log((n-m)!).") |
|---|
| 113 | |
|---|
| 114 | (defmfun pochammer (a x) |
|---|
| 115 | "gsl_sf_poch_e" ((a :double) (x :double) (ret sf-result)) |
|---|
| 116 | :documentation ; FDL |
|---|
| 117 | "The Pochhammer symbol (a)_x := Gamma(a + |
|---|
| 118 | x)/Gamma(a), subject to a and a+x not being negative |
|---|
| 119 | integers. The Pochhammer symbol is also known as the Apell symbol and |
|---|
| 120 | sometimes written as (a,x).") |
|---|
| 121 | |
|---|
| 122 | (defmfun log-pochammer (a x) |
|---|
| 123 | "gsl_sf_lnpoch_e" ((a :double) (x :double) (ret sf-result)) |
|---|
| 124 | :documentation ; FDL |
|---|
| 125 | "The logarithm of the Pochhammer symbol, |
|---|
| 126 | log((a)_x) = log(Gamma(a + x)/Gamma(a)) for a > 0, a+x > 0.") |
|---|
| 127 | |
|---|
| 128 | (defmfun log-pochammer-sign (a x) |
|---|
| 129 | "gsl_sf_lnpoch_sgn_e" |
|---|
| 130 | ((a :double) (x :double) (ret sf-result) (sign :double)) |
|---|
| 131 | :documentation ; FDL |
|---|
| 132 | "The logarithm of the Pochhammer symbol and its sign. |
|---|
| 133 | The computed parameters are result = |
|---|
| 134 | log(|(a)_x|) and sgn = sgn((a)_x) where (a)_x := |
|---|
| 135 | Gamma(a + x)/Gamma(a), subject to a, a+x not being negative integers." |
|---|
| 136 | :return ((val ret) (dcref sign) (err ret))) |
|---|
| 137 | |
|---|
| 138 | (defmfun relative-pochammer (a x) |
|---|
| 139 | "gsl_sf_pochrel_e" ((a :double) (x :double) (ret sf-result)) |
|---|
| 140 | :documentation ; FDL |
|---|
| 141 | "The relative Pochhammer symbol ((a)_x - |
|---|
| 142 | 1)/x where (a)_x := Gamma(a + x)/Gamma(a)}.") |
|---|
| 143 | |
|---|
| 144 | (defmfun incomplete-gamma (a x) |
|---|
| 145 | "gsl_sf_gamma_inc_Q_e" ((a :double) (x :double) (ret sf-result)) |
|---|
| 146 | :documentation ; FDL |
|---|
| 147 | "The normalized incomplete Gamma Function |
|---|
| 148 | Q(a,x) = 1/Gamma(a) \int_x^\infty dt t^{a-1} \exp(-t) for a > 0, x >= 0.") |
|---|
| 149 | |
|---|
| 150 | (defmfun complementary-incomplete-gamma (a x) |
|---|
| 151 | "gsl_sf_gamma_inc_P_e" ((a :double) (x :double) (ret sf-result)) |
|---|
| 152 | :documentation ; FDL |
|---|
| 153 | "The complementary normalized incomplete Gamma Function |
|---|
| 154 | P(a,x) = 1/\Gamma(a) \int_0^x dt t^{a-1} \exp(-t)} |
|---|
| 155 | for a > 0, x >= 0. Note that Abramowitz & Stegun |
|---|
| 156 | call P(a,x) the incomplete gamma function (section 6.5).") |
|---|
| 157 | |
|---|
| 158 | (defmfun nonnormalized-incomplete-gamma (a x) |
|---|
| 159 | "gsl_sf_gamma_inc_e" ((a :double) (x :double) (ret sf-result)) |
|---|
| 160 | :documentation ; FDL |
|---|
| 161 | "The incomplete Gamma Function |
|---|
| 162 | Gamma(a,x), without the normalization factor |
|---|
| 163 | included in the previously defined functions: |
|---|
| 164 | Gamma(a,x) = \int_x^\infty dt t^{a-1} \exp(-t) |
|---|
| 165 | for a real and x >= 0.") |
|---|
| 166 | |
|---|
| 167 | (defmfun beta (a b) |
|---|
| 168 | "gsl_sf_beta_e" ((a :double) (b :double) (ret sf-result)) |
|---|
| 169 | :documentation ; FDL |
|---|
| 170 | "The Beta Function, B(a,b) = Gamma(a)Gamma(b)/Gamma(a+b)} for a > 0, b > 0.") |
|---|
| 171 | |
|---|
| 172 | (defmfun log-beta (a b) |
|---|
| 173 | "gsl_sf_lnbeta_e" ((a :double) (b :double) (ret sf-result)) |
|---|
| 174 | :documentation ; FDL |
|---|
| 175 | "The logarithm of the Beta Function, log(B(a,b)) for a > 0, b > 0.") |
|---|
| 176 | |
|---|
| 177 | (defmfun incomplete-beta (a b x) |
|---|
| 178 | "gsl_sf_beta_inc_e" |
|---|
| 179 | ((a :double) (b :double) (x :double) (ret sf-result)) |
|---|
| 180 | :documentation ; FDL |
|---|
| 181 | "The normalized incomplete Beta function |
|---|
| 182 | B_x(a,b)/B(a,b) where |
|---|
| 183 | B_x(a,b) = \int_0^x t^{a-1} (1-t)^{b-1} dt |
|---|
| 184 | for a > 0, b > 0, and 0 <= x <= 1.") |
|---|
| 185 | |
|---|
| 186 | ;;;;**************************************************************************** |
|---|
| 187 | ;;;; Examples and unit test |
|---|
| 188 | ;;;;**************************************************************************** |
|---|
| 189 | |
|---|
| 190 | #| |
|---|
| 191 | (make-tests gamma |
|---|
| 192 | (gamma -1.0d0) |
|---|
| 193 | (gamma 6.0d0) |
|---|
| 194 | (log-gamma -100.0d0) |
|---|
| 195 | (log-gamma 100.0d0) |
|---|
| 196 | (log-gamma-sign 100.0d0) |
|---|
| 197 | (gamma* 24.0d0) |
|---|
| 198 | (1/gamma 8.0d0) |
|---|
| 199 | (log-gamma-complex #C(10.0d0 10.0d0)) |
|---|
| 200 | (taylor-coefficient 12 3.0d0) |
|---|
| 201 | (factorial 12) |
|---|
| 202 | (double-factorial 12) |
|---|
| 203 | (log-factorial 199) |
|---|
| 204 | (log-double-factorial 199) |
|---|
| 205 | (choose 8 3) |
|---|
| 206 | (choose 3 8) |
|---|
| 207 | (log-choose 67 12) |
|---|
| 208 | (pochammer 3.0d0 2.0d0) |
|---|
| 209 | (log-pochammer 2.0d0 199.0d0) |
|---|
| 210 | (log-pochammer-sign 2.0d0 199.0d0) |
|---|
| 211 | (relative-pochammer 2.0d0 9.0d0) |
|---|
| 212 | (incomplete-gamma 2.0d0 2.0d0) |
|---|
| 213 | (complementary-incomplete-gamma 2.0d0 2.0d0) |
|---|
| 214 | (nonnormalized-incomplete-gamma 2.0d0 2.0d0) |
|---|
| 215 | (beta 5.50d0 1.0d0) |
|---|
| 216 | (log-beta 5.5d0 1.0d0) |
|---|
| 217 | (incomplete-beta 1.0d0 1.50d0 0.50d0)) |
|---|
| 218 | |# |
|---|
| 219 | |
|---|
| 220 | (LISP-UNIT:DEFINE-TEST GAMMA |
|---|
| 221 | (LISP-UNIT:ASSERT-ERROR 'GSL-CONDITION (GAMMA -1.0d0)) |
|---|
| 222 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 223 | (LIST 120.0d0 2.6645352591003757d-14) |
|---|
| 224 | (MULTIPLE-VALUE-LIST (GAMMA 6.0d0))) |
|---|
| 225 | (LISP-UNIT:ASSERT-ERROR 'GSL-CONDITION (LOG-GAMMA -100.0d0)) |
|---|
| 226 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 227 | (LIST 359.13420536957534d0 2.4544868717695813d-13) |
|---|
| 228 | (MULTIPLE-VALUE-LIST (LOG-GAMMA 100.0d0))) |
|---|
| 229 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 230 | (LIST 359.13420536957534d0 1.0d0 |
|---|
| 231 | 2.4544868717695813d-13) |
|---|
| 232 | (MULTIPLE-VALUE-LIST (LOG-GAMMA-SIGN 100.0d0))) |
|---|
| 233 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 234 | (LIST 1.0034780558311105d0 4.456337769159149d-16) |
|---|
| 235 | (MULTIPLE-VALUE-LIST (GAMMA* 24.0d0))) |
|---|
| 236 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 237 | (LIST 1.984126984126984d-4 1.3216940769347103d-19) |
|---|
| 238 | (MULTIPLE-VALUE-LIST (1/GAMMA 8.0d0))) |
|---|
| 239 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 240 | (LIST 8.236131750448724d0 -1.1840378149363078d0 |
|---|
| 241 | 7.315154482555574d-15 2.1796539969587586d-14) |
|---|
| 242 | (MULTIPLE-VALUE-LIST |
|---|
| 243 | (LOG-GAMMA-COMPLEX #C(10.0d0 10.0d0)))) |
|---|
| 244 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 245 | (LIST 0.0011094764610389606d0 2.956239149580215d-18) |
|---|
| 246 | (MULTIPLE-VALUE-LIST (TAYLOR-COEFFICIENT 12 3.0d0))) |
|---|
| 247 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 248 | (LIST 4.790016d8 0.0d0) |
|---|
| 249 | (MULTIPLE-VALUE-LIST (FACTORIAL 12))) |
|---|
| 250 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 251 | (LIST 46080.0d0 0.0d0) |
|---|
| 252 | (MULTIPLE-VALUE-LIST (DOUBLE-FACTORIAL 12))) |
|---|
| 253 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 254 | (LIST 857.9336698258575d0 5.777158772429952d-13) |
|---|
| 255 | (MULTIPLE-VALUE-LIST (LOG-FACTORIAL 199))) |
|---|
| 256 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 257 | (LIST 430.17789358084747d0 1.9103736085528287d-13) |
|---|
| 258 | (MULTIPLE-VALUE-LIST (LOG-DOUBLE-FACTORIAL 199))) |
|---|
| 259 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 260 | (LIST 56.0d0 7.460698725481052d-14) |
|---|
| 261 | (MULTIPLE-VALUE-LIST (CHOOSE 8 3))) |
|---|
| 262 | (LISP-UNIT:ASSERT-ERROR 'GSL-CONDITION (CHOOSE 3 8)) |
|---|
| 263 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 264 | (LIST 29.422274169864693d0 1.9338924605168215d-13) |
|---|
| 265 | (MULTIPLE-VALUE-LIST (LOG-CHOOSE 67 12))) |
|---|
| 266 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 267 | (LIST 12.0d0 6.927791673660977d-14) |
|---|
| 268 | (MULTIPLE-VALUE-LIST (POCHAMMER 3.0d0 2.0d0))) |
|---|
| 269 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 270 | (LIST 863.2319871924054d0 9.645972767118375d-13) |
|---|
| 271 | (MULTIPLE-VALUE-LIST (LOG-POCHAMMER 2.0d0 199.0d0))) |
|---|
| 272 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 273 | (LIST 863.2319871924054d0 1.0d0 9.645972767118375d-13) |
|---|
| 274 | (MULTIPLE-VALUE-LIST |
|---|
| 275 | (LOG-POCHAMMER-SIGN 2.0d0 199.0d0))) |
|---|
| 276 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 277 | (LIST 403199.88888888917d0 3.5998302729212807d-9) |
|---|
| 278 | (MULTIPLE-VALUE-LIST (RELATIVE-POCHAMMER 2.0d0 9.0d0))) |
|---|
| 279 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 280 | (LIST 0.40600584970983766d0 9.568405127077496d-16) |
|---|
| 281 | (MULTIPLE-VALUE-LIST (INCOMPLETE-GAMMA 2.0d0 2.0d0))) |
|---|
| 282 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 283 | (LIST 0.5939941502901611d0 3.510166705531295d-15) |
|---|
| 284 | (MULTIPLE-VALUE-LIST |
|---|
| 285 | (COMPLEMENTARY-INCOMPLETE-GAMMA 2.0d0 2.0d0))) |
|---|
| 286 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 287 | (LIST 0.40600584970983766d0 1.2272947381959672d-15) |
|---|
| 288 | (MULTIPLE-VALUE-LIST |
|---|
| 289 | (NONNORMALIZED-INCOMPLETE-GAMMA 2.0d0 2.0d0))) |
|---|
| 290 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 291 | (LIST 0.1818181818181818d0 1.0189782228738177d-15) |
|---|
| 292 | (MULTIPLE-VALUE-LIST (BETA 5.5d0 1.0d0))) |
|---|
| 293 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 294 | (LIST -1.7047480922384253d0 3.81791013808375d-15) |
|---|
| 295 | (MULTIPLE-VALUE-LIST (LOG-BETA 5.5d0 1.0d0))) |
|---|
| 296 | (LISP-UNIT::ASSERT-NUMERICAL-EQUAL |
|---|
| 297 | (LIST 0.6464466094067263d0 1.0178662453689468d-14) |
|---|
| 298 | (MULTIPLE-VALUE-LIST |
|---|
| 299 | (INCOMPLETE-BETA 1.0d0 1.5d0 0.5d0)))) |
|---|