igamma_temme_large_coef.cpp 5.1 KB

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