source: sasview/sansmodels/src/sans/models/c_models/gamma_win.c @ 2c63e80e

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 2c63e80e was 2c63e80e, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Re #5 fixing samsmodels compilation on MSVC

  • Property mode set to 100644
File size: 4.0 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>
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  double temp;
56
57  if (x < 0.001)
58      return 1.0/(x*(1.0 + gamma*x));
59
60  ///////////////////////////////////////////////////////////////////////////
61  // Second interval: [0.001, 12)
62
63  if (x < 12.0)
64    {
65      // The algorithm directly approximates gamma over (1,2) and uses
66      // reduction identities to reduce other arguments to this interval.
67
68      y = x;
69
70      if (y < 1.0) arg_was_less_than_one = 1;
71
72      // Add or subtract integers as necessary to bring y into (1,2)
73      // Will correct for this below
74      if (arg_was_less_than_one==1) {
75          y += 1.0;
76      } else {
77          n = static_cast<int> (floor(y)) - 1;  // will use n later
78          y -= n;
79      }
80
81      z = y - 1;
82      for (i = 0; i < 8; i++) {
83          num = (num + p[i])*z;
84          den = den*z + q[i];
85      }
86      result = num/den + 1.0;
87
88      // Apply correction if argument was not initially in (1,2)
89      if (arg_was_less_than_one==1) {
90          // Use identity gamma(z) = gamma(z+1)/z
91          // The variable "result" now holds gamma of the original y + 1
92          // Thus we use y-1 to get back the orginal y.
93          result /= (y-1.0);
94      } else {
95          // Use the identity gamma(z+n) = z*(z+1)* ... *(z+n-1)*gamma(z)
96          for (i = 0; i < n; i++)
97              result *= y++;
98      }
99
100      return result;
101    }
102
103    ///////////////////////////////////////////////////////////////////////////
104    // Third interval: [12, infinity)
105
106    if (x > 171.624)
107    {
108      // Correct answer too large to display. Force +infinity.
109      temp = DBL_MAX;
110      return temp*2.0;
111    }
112
113    return exp(lgamma(x));
114}
115
116double lgamma (double x)
117{
118  static const double c[8] =
119  {
120   1.0/12.0,
121  -1.0/360.0,
122  1.0/1260.0,
123  -1.0/1680.0,
124  1.0/1188.0,
125  -691.0/360360.0,
126  1.0/156.0,
127  -3617.0/122400.0
128  };
129  double z = 1.0/(x*x);
130  double sum = c[7];
131  static const double halfLogTwoPi = 0.91893853320467274178032973640562;
132  double series;
133  double logGamma;
134
135  if (x < 12.0) {
136     return log(fabs(gamma(x)));
137  }
138
139  // Abramowitz and Stegun 6.1.41
140  // Asymptotic series should be good to at least 11 or 12 figures
141  // For error analysis, see Whittiker and Watson
142  // A Course in Modern Analysis (1927), page 252
143
144  for (int i=6; i >= 0; i--) {
145      sum *= z;
146      sum += c[i];
147  }
148  series = sum/x;
149  logGamma = (x - 0.5)*log(x) - x + halfLogTwoPi + series;
150  return logGamma;
151}
Note: See TracBrowser for help on using the repository browser.