]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/math/tools/igamma_temme_large_coef.cpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / math / tools / igamma_temme_large_coef.cpp
1 // Copyright John Maddock 2006.
2 // Use, modification and distribution are subject to the
3 // Boost Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <boost/math/special_functions/log1p.hpp>
7 #include <boost/math/special_functions/erf.hpp>
8 #include <boost/math/constants/constants.hpp>
9 #include <map>
10 #include <iostream>
11 #include <iomanip>
12 #include "mp_t.hpp"
13
14 using namespace std;
15 using namespace boost::math;
16
17 //
18 // This program calculates the coefficients of the polynomials
19 // used for the regularized incomplete gamma functions gamma_p
20 // and gamma_q when parameter a is large, and sigma is small
21 // (where sigma = fabs(1 - x/a) ).
22 //
23 // See "The Asymptotic Expansion of the Incomplete Gamma Functions"
24 // N. M. Temme.
25 // Siam J. Math Anal. Vol 10 No 4, July 1979, p757.
26 // Coeffient calculation is described from Eq 3.8 (p762) onwards.
27 //
28
29 //
30 // Alpha:
31 //
32 mp_t alpha(unsigned k)
33 {
34 static map<unsigned, mp_t> data;
35 if(data.empty())
36 {
37 data[1] = 1;
38 }
39
40 map<unsigned, mp_t>::const_iterator pos = data.find(k);
41 if(pos != data.end())
42 return (*pos).second;
43 //
44 // OK try and calculate the value:
45 //
46 mp_t result = alpha(k-1);
47 for(unsigned j = 2; j <= k-1; ++j)
48 {
49 result -= j * alpha(j) * alpha(k-j+1);
50 }
51 result /= (k+1);
52 data[k] = result;
53 return result;
54 }
55
56 mp_t gamma(unsigned k)
57 {
58 static map<unsigned, mp_t> data;
59
60 map<unsigned, mp_t>::const_iterator pos = data.find(k);
61 if(pos != data.end())
62 return (*pos).second;
63
64 mp_t result = (k&1) ? -1 : 1;
65
66 for(unsigned i = 1; i <= (2 * k + 1); i += 2)
67 result *= i;
68 result *= alpha(2 * k + 1);
69 data[k] = result;
70 return result;
71 }
72
73 mp_t Coeff(unsigned n, unsigned k)
74 {
75 map<unsigned, map<unsigned, mp_t> > data;
76 if(data.empty())
77 data[0][0] = mp_t(-1) / 3;
78
79 map<unsigned, map<unsigned, mp_t> >::const_iterator p1 = data.find(n);
80 if(p1 != data.end())
81 {
82 map<unsigned, mp_t>::const_iterator p2 = p1->second.find(k);
83 if(p2 != p1->second.end())
84 {
85 return p2->second;
86 }
87 }
88
89 //
90 // If we don't have the value, calculate it:
91 //
92 if(k == 0)
93 {
94 // special case:
95 mp_t result = (n+2) * alpha(n+2);
96 data[n][k] = result;
97 return result;
98 }
99 // general case:
100 mp_t result = gamma(k) * Coeff(n, 0) + (n+2) * Coeff(n+2, k-1);
101 data[n][k] = result;
102 return result;
103 }
104
105 void calculate_terms(double sigma, double a, unsigned bits)
106 {
107 cout << endl << endl;
108 cout << "Sigma: " << sigma << endl;
109 cout << "A: " << a << endl;
110 double lambda = 1 - sigma;
111 cout << "Lambda: " << lambda << endl;
112 double y = a * (-sigma - log1p(-sigma));
113 cout << "Y: " << y << endl;
114 double z = -sqrt(2 * (-sigma - log1p(-sigma)));
115 cout << "Z: " << z << endl;
116 double dom = erfc(sqrt(y)) / 2;
117 cout << "Erfc term: " << dom << endl;
118 double lead = exp(-y) / sqrt(2 * constants::pi<double>() * a);
119 cout << "Remainder factor: " << lead << endl;
120 double eps = ldexp(1.0, 1 - static_cast<int>(bits));
121 double target = dom * eps / lead;
122 cout << "Target smallest term: " << target << endl;
123
124 unsigned max_n = 0;
125
126 for(unsigned n = 0; n < 10000; ++n)
127 {
128 double term = tools::real_cast<double>(Coeff(n, 0) * pow(z, (double)n));
129 if(fabs(term) < target)
130 {
131 max_n = n-1;
132 break;
133 }
134 }
135 cout << "Max n required: " << max_n << endl;
136
137 unsigned max_k;
138 for(unsigned k = 1; k < 10000; ++k)
139 {
140 double term = tools::real_cast<double>(Coeff(0, k) * pow(a, -((double)k)));
141 if(fabs(term) < target)
142 {
143 max_k = k-1;
144 break;
145 }
146 }
147 cout << "Max k required: " << max_k << endl << endl;
148
149 bool code = false;
150 cout << "Print code [0|1]? ";
151 cin >> code;
152
153 int prec = 2 + (static_cast<double>(bits) * 3010LL)/10000;
154 std::cout << std::scientific << std::setprecision(40);
155
156 if(code)
157 {
158 cout << " T workspace[" << max_k+1 << "];\n\n";
159 for(unsigned k = 0; k <= max_k; ++k)
160 {
161 cout <<
162 " static const T C" << k << "[] = {\n";
163 for(unsigned n = 0; n < 10000; ++n)
164 {
165 double term = tools::real_cast<double>(Coeff(n, k) * pow(a, -((double)k)) * pow(z, (double)n));
166 if(fabs(term) < target)
167 {
168 break;
169 }
170 cout << " " << Coeff(n, k) << "L,\n";
171 }
172 cout <<
173 " };\n"
174 " workspace[" << k << "] = tools::evaluate_polynomial(C" << k << ", z);\n\n";
175 }
176 cout << " T result = tools::evaluate_polynomial(workspace, 1/a);\n\n";
177 }
178 }
179
180
181 int main()
182 {
183 bool cont;
184 do{
185 cont = false;
186 double sigma;
187 cout << "Enter max value for sigma (sigma = |1 - x/a|): ";
188 cin >> sigma;
189 double a;
190 cout << "Enter min value for a: ";
191 cin >> a;
192 unsigned precision;
193 cout << "Enter number of bits precision required: ";
194 cin >> precision;
195
196 calculate_terms(sigma, a, precision);
197
198 cout << "Try again[0|1]: ";
199 cin >> cont;
200
201 }while(cont);
202
203
204 return 0;
205 }
206