source: sasview/src/sas/models/c_extension/c_models/gamma_win.c @ 573e7034

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 573e7034 was 79492222, checked in by krzywon, 10 years ago

Changed the file and folder names to remove all SANS references.

  • Property mode set to 100644
File size: 3.8 KB
Line 
1// Visit http://www.johndcook.com/stand_alone_code.html for the source of this code and more like it.
2// Modified for the DANSE project.
3
4#include <math.h>
5
6#include "gamma_win.h"
7
8// Note that the functions Gamma and LogGamma are mutually dependent.
9
10double gamma(double x)
11{
12  // Split the function domain into three intervals:
13  // (0, 0.001), [0.001, 12), and (12, infinity)
14
15  ///////////////////////////////////////////////////////////////////////////
16  // First interval: (0, 0.001)
17  //
18  // For small x, 1/Gamma(x) has power series x + gamma x^2  - ...
19  // So in this range, 1/Gamma(x) = x + gamma x^2 with error on the order of x^3.
20  // The relative error over this interval is less than 6e-7.
21
22  const double gamma = 0.577215664901532860606512090; // Euler's gamma constant
23  double y;
24  int arg_was_less_than_one = 0;
25  int n = 0;
26  // numerator coefficients for approximation over the interval (1,2)
27  static const double p[] =
28  {
29      -1.71618513886549492533811E+0,
30       2.47656508055759199108314E+1,
31      -3.79804256470945635097577E+2,
32       6.29331155312818442661052E+2,
33       8.66966202790413211295064E+2,
34      -3.14512729688483675254357E+4,
35      -3.61444134186911729807069E+4,
36       6.64561438202405440627855E+4
37  };
38  // denominator coefficients for approximation over the interval (1,2)
39  static const double q[] =
40  {
41      -3.08402300119738975254353E+1,
42       3.15350626979604161529144E+2,
43      -1.01515636749021914166146E+3,
44      -3.10777167157231109440444E+3,
45       2.25381184209801510330112E+4,
46       4.75584627752788110767815E+3,
47      -1.34659959864969306392456E+5,
48      -1.15132259675553483497211E+5
49  };
50  double num = 0.0;
51  double den = 1.0;
52  int i;
53  double z;
54  double result;
55
56  if (x < 0.001)
57      return 1.0/(x*(1.0 + gamma*x));
58
59  ///////////////////////////////////////////////////////////////////////////
60  // Second interval: [0.001, 12)
61
62  if (x < 12.0)
63    {
64      // The algorithm directly approximates gamma over (1,2) and uses
65      // reduction identities to reduce other arguments to this interval.
66
67      y = x;
68
69      if (y < 1.0) arg_was_less_than_one = 1;
70
71      // Add or subtract integers as necessary to bring y into (1,2)
72      // Will correct for this below
73      if (arg_was_less_than_one==1) {
74          y += 1.0;
75      } else {
76          n = (int) (floor(y)) - 1;  // will use n later
77          y -= n;
78      }
79
80      z = y - 1;
81      for (i = 0; i < 8; i++) {
82          num = (num + p[i])*z;
83          den = den*z + q[i];
84      }
85      result = num/den + 1.0;
86
87      // Apply correction if argument was not initially in (1,2)
88      if (arg_was_less_than_one==1) {
89          // Use identity gamma(z) = gamma(z+1)/z
90          // The variable "result" now holds gamma of the original y + 1
91          // Thus we use y-1 to get back the orginal y.
92          result /= (y-1.0);
93      } else {
94          // Use the identity gamma(z+n) = z*(z+1)* ... *(z+n-1)*gamma(z)
95          for (i = 0; i < n; i++)
96              result *= y++;
97      }
98
99      return result;
100    }
101
102    return exp(lgamma(x));
103}
104
105double lgamma (double x)
106{
107  static const double c[8] =
108  {
109   1.0/12.0,
110  -1.0/360.0,
111  1.0/1260.0,
112  -1.0/1680.0,
113  1.0/1188.0,
114  -691.0/360360.0,
115  1.0/156.0,
116  -3617.0/122400.0
117  };
118  double z = 1.0/(x*x);
119  double sum = c[7];
120  static const double halfLogTwoPi = 0.91893853320467274178032973640562;
121  double series;
122  double logGamma;
123  int i;
124
125  if (x < 12.0) {
126     return log(fabs(gamma(x)));
127  }
128
129  // Abramowitz and Stegun 6.1.41
130  // Asymptotic series should be good to at least 11 or 12 figures
131  // For error analysis, see Whittiker and Watson
132  // A Course in Modern Analysis (1927), page 252
133
134  for (i=6; i >= 0; i--) {
135      sum *= z;
136      sum += c[i];
137  }
138  series = sum/x;
139  logGamma = (x - 0.5)*log(x) - x + halfLogTwoPi + series;
140  return logGamma;
141}
Note: See TracBrowser for help on using the repository browser.