gamma.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package math
  5. // The original C code, the long comment, and the constants
  6. // below are from http://netlib.sandia.gov/cephes/cprob/gamma.c.
  7. // The go code is a simplified version of the original C.
  8. //
  9. // tgamma.c
  10. //
  11. // Gamma function
  12. //
  13. // SYNOPSIS:
  14. //
  15. // double x, y, tgamma();
  16. // extern int signgam;
  17. //
  18. // y = tgamma( x );
  19. //
  20. // DESCRIPTION:
  21. //
  22. // Returns gamma function of the argument. The result is
  23. // correctly signed, and the sign (+1 or -1) is also
  24. // returned in a global (extern) variable named signgam.
  25. // This variable is also filled in by the logarithmic gamma
  26. // function lgamma().
  27. //
  28. // Arguments |x| <= 34 are reduced by recurrence and the function
  29. // approximated by a rational function of degree 6/7 in the
  30. // interval (2,3). Large arguments are handled by Stirling's
  31. // formula. Large negative arguments are made positive using
  32. // a reflection formula.
  33. //
  34. // ACCURACY:
  35. //
  36. // Relative error:
  37. // arithmetic domain # trials peak rms
  38. // DEC -34, 34 10000 1.3e-16 2.5e-17
  39. // IEEE -170,-33 20000 2.3e-15 3.3e-16
  40. // IEEE -33, 33 20000 9.4e-16 2.2e-16
  41. // IEEE 33, 171.6 20000 2.3e-15 3.2e-16
  42. //
  43. // Error for arguments outside the test range will be larger
  44. // owing to error amplification by the exponential function.
  45. //
  46. // Cephes Math Library Release 2.8: June, 2000
  47. // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
  48. //
  49. // The readme file at http://netlib.sandia.gov/cephes/ says:
  50. // Some software in this archive may be from the book _Methods and
  51. // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
  52. // International, 1989) or from the Cephes Mathematical Library, a
  53. // commercial product. In either event, it is copyrighted by the author.
  54. // What you see here may be used freely but it comes with no support or
  55. // guarantee.
  56. //
  57. // The two known misprints in the book are repaired here in the
  58. // source listings for the gamma function and the incomplete beta
  59. // integral.
  60. //
  61. // Stephen L. Moshier
  62. // moshier@na-net.ornl.gov
  63. var _gamP = [...]float64{
  64. 1.60119522476751861407e-04,
  65. 1.19135147006586384913e-03,
  66. 1.04213797561761569935e-02,
  67. 4.76367800457137231464e-02,
  68. 2.07448227648435975150e-01,
  69. 4.94214826801497100753e-01,
  70. 9.99999999999999996796e-01,
  71. }
  72. var _gamQ = [...]float64{
  73. -2.31581873324120129819e-05,
  74. 5.39605580493303397842e-04,
  75. -4.45641913851797240494e-03,
  76. 1.18139785222060435552e-02,
  77. 3.58236398605498653373e-02,
  78. -2.34591795718243348568e-01,
  79. 7.14304917030273074085e-02,
  80. 1.00000000000000000320e+00,
  81. }
  82. var _gamS = [...]float64{
  83. 7.87311395793093628397e-04,
  84. -2.29549961613378126380e-04,
  85. -2.68132617805781232825e-03,
  86. 3.47222221605458667310e-03,
  87. 8.33333333333482257126e-02,
  88. }
  89. // Gamma function computed by Stirling's formula.
  90. // The polynomial is valid for 33 <= x <= 172.
  91. func stirling(x float64) float64 {
  92. const (
  93. SqrtTwoPi = 2.506628274631000502417
  94. MaxStirling = 143.01608
  95. )
  96. w := 1 / x
  97. w = 1 + w*((((_gamS[0]*w+_gamS[1])*w+_gamS[2])*w+_gamS[3])*w+_gamS[4])
  98. y := Exp(x)
  99. if x > MaxStirling { // avoid Pow() overflow
  100. v := Pow(x, 0.5*x-0.25)
  101. y = v * (v / y)
  102. } else {
  103. y = Pow(x, x-0.5) / y
  104. }
  105. y = SqrtTwoPi * y * w
  106. return y
  107. }
  108. // Gamma returns the Gamma function of x.
  109. //
  110. // Special cases are:
  111. // Gamma(+Inf) = +Inf
  112. // Gamma(+0) = +Inf
  113. // Gamma(-0) = -Inf
  114. // Gamma(x) = NaN for integer x < 0
  115. // Gamma(-Inf) = NaN
  116. // Gamma(NaN) = NaN
  117. func Gamma(x float64) float64 {
  118. const Euler = 0.57721566490153286060651209008240243104215933593992 // A001620
  119. // special cases
  120. switch {
  121. case isNegInt(x) || IsInf(x, -1) || IsNaN(x):
  122. return NaN()
  123. case x == 0:
  124. if Signbit(x) {
  125. return Inf(-1)
  126. }
  127. return Inf(1)
  128. case x < -170.5674972726612 || x > 171.61447887182298:
  129. return Inf(1)
  130. }
  131. q := Abs(x)
  132. p := Floor(q)
  133. if q > 33 {
  134. if x >= 0 {
  135. return stirling(x)
  136. }
  137. signgam := 1
  138. if ip := int(p); ip&1 == 0 {
  139. signgam = -1
  140. }
  141. z := q - p
  142. if z > 0.5 {
  143. p = p + 1
  144. z = q - p
  145. }
  146. z = q * Sin(Pi*z)
  147. if z == 0 {
  148. return Inf(signgam)
  149. }
  150. z = Pi / (Abs(z) * stirling(q))
  151. return float64(signgam) * z
  152. }
  153. // Reduce argument
  154. z := 1.0
  155. for x >= 3 {
  156. x = x - 1
  157. z = z * x
  158. }
  159. for x < 0 {
  160. if x > -1e-09 {
  161. goto small
  162. }
  163. z = z / x
  164. x = x + 1
  165. }
  166. for x < 2 {
  167. if x < 1e-09 {
  168. goto small
  169. }
  170. z = z / x
  171. x = x + 1
  172. }
  173. if x == 2 {
  174. return z
  175. }
  176. x = x - 2
  177. p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6]
  178. q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7]
  179. return z * p / q
  180. small:
  181. if x == 0 {
  182. return Inf(1)
  183. }
  184. return z / ((1 + Euler*x) * x)
  185. }
  186. func isNegInt(x float64) bool {
  187. if x < 0 {
  188. _, xf := Modf(x)
  189. return xf == 0
  190. }
  191. return false
  192. }