f.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. // (C) 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. #define L22
  6. //#include "../tools/ntl_rr_lanczos.hpp"
  7. //#include "../tools/ntl_rr_digamma.hpp"
  8. #include "multiprecision.hpp"
  9. #include <boost/math/tools/polynomial.hpp>
  10. #include <boost/math/special_functions.hpp>
  11. #include <boost/math/special_functions/zeta.hpp>
  12. #include <boost/math/special_functions/expint.hpp>
  13. #include <boost/math/special_functions/lambert_w.hpp>
  14. #include <cmath>
  15. mp_type f(const mp_type& x, int variant)
  16. {
  17. static const mp_type tiny = boost::math::tools::min_value<mp_type>() * 64;
  18. switch(variant)
  19. {
  20. case 0:
  21. {
  22. mp_type x_ = sqrt(x == 0 ? 1e-80 : x);
  23. return boost::math::erf(x_) / x_;
  24. }
  25. case 1:
  26. {
  27. mp_type x_ = 1 / x;
  28. return boost::math::erfc(x_) * x_ / exp(-x_ * x_);
  29. }
  30. case 2:
  31. {
  32. return boost::math::erfc(x) * x / exp(-x * x);
  33. }
  34. case 3:
  35. {
  36. mp_type y(x);
  37. if(y == 0)
  38. y += tiny;
  39. return boost::math::lgamma(y+2) / y - 0.5;
  40. }
  41. case 4:
  42. //
  43. // lgamma in the range [2,3], use:
  44. //
  45. // lgamma(x) = (x-2) * (x + 1) * (c + R(x - 2))
  46. //
  47. // Works well at 80-bit long double precision, but doesn't
  48. // stretch to 128-bit precision.
  49. //
  50. if(x == 0)
  51. {
  52. return boost::lexical_cast<mp_type>("0.42278433509846713939348790991759756895784066406008") / 3;
  53. }
  54. return boost::math::lgamma(x+2) / (x * (x+3));
  55. case 5:
  56. {
  57. //
  58. // lgamma in the range [1,2], use:
  59. //
  60. // lgamma(x) = (x - 1) * (x - 2) * (c + R(x - 1))
  61. //
  62. // works well over [1, 1.5] but not near 2 :-(
  63. //
  64. mp_type r1 = boost::lexical_cast<mp_type>("0.57721566490153286060651209008240243104215933593992");
  65. mp_type r2 = boost::lexical_cast<mp_type>("0.42278433509846713939348790991759756895784066406008");
  66. if(x == 0)
  67. {
  68. return r1;
  69. }
  70. if(x == 1)
  71. {
  72. return r2;
  73. }
  74. return boost::math::lgamma(x+1) / (x * (x - 1));
  75. }
  76. case 6:
  77. {
  78. //
  79. // lgamma in the range [1.5,2], use:
  80. //
  81. // lgamma(x) = (2 - x) * (1 - x) * (c + R(2 - x))
  82. //
  83. // works well over [1.5, 2] but not near 1 :-(
  84. //
  85. mp_type r1 = boost::lexical_cast<mp_type>("0.57721566490153286060651209008240243104215933593992");
  86. mp_type r2 = boost::lexical_cast<mp_type>("0.42278433509846713939348790991759756895784066406008");
  87. if(x == 0)
  88. {
  89. return r2;
  90. }
  91. if(x == 1)
  92. {
  93. return r1;
  94. }
  95. return boost::math::lgamma(2-x) / (x * (x - 1));
  96. }
  97. case 7:
  98. {
  99. //
  100. // erf_inv in range [0, 0.5]
  101. //
  102. mp_type y = x;
  103. if(y == 0)
  104. y = boost::math::tools::epsilon<mp_type>() / 64;
  105. return boost::math::erf_inv(y) / (y * (y+10));
  106. }
  107. case 8:
  108. {
  109. //
  110. // erfc_inv in range [0.25, 0.5]
  111. // Use an y-offset of 0.25, and range [0, 0.25]
  112. // abs error, auto y-offset.
  113. //
  114. mp_type y = x;
  115. if(y == 0)
  116. y = boost::lexical_cast<mp_type>("1e-5000");
  117. return sqrt(-2 * log(y)) / boost::math::erfc_inv(y);
  118. }
  119. case 9:
  120. {
  121. mp_type x2 = x;
  122. if(x2 == 0)
  123. x2 = boost::lexical_cast<mp_type>("1e-5000");
  124. mp_type y = exp(-x2*x2); // sqrt(-log(x2)) - 5;
  125. return boost::math::erfc_inv(y) / x2;
  126. }
  127. case 10:
  128. {
  129. //
  130. // Digamma over the interval [1,2], set x-offset to 1
  131. // and optimise for absolute error over [0,1].
  132. //
  133. int current_precision = get_working_precision();
  134. if(current_precision < 1000)
  135. set_working_precision(1000);
  136. //
  137. // This value for the root of digamma is calculated using our
  138. // differentiated lanczos approximation. It agrees with Cody
  139. // to ~ 25 digits and to Morris to 35 digits. See:
  140. // TOMS ALGORITHM 708 (Didonato and Morris).
  141. // and Math. Comp. 27, 123-127 (1973) by Cody, Strecok and Thacher.
  142. //
  143. //mp_type root = boost::lexical_cast<mp_type>("1.4616321449683623412626595423257213234331845807102825466429633351908372838889871");
  144. //
  145. // Actually better to calculate the root on the fly, it appears to be more
  146. // accurate: convergence is easier with the 1000-bit value, the approximation
  147. // produced agrees with functions.mathworld.com values to 35 digits even quite
  148. // near the root.
  149. //
  150. static boost::math::tools::eps_tolerance<mp_type> tol(1000);
  151. static boost::uintmax_t max_iter = 1000;
  152. mp_type (*pdg)(mp_type) = &boost::math::digamma;
  153. static const mp_type root = boost::math::tools::bracket_and_solve_root(pdg, mp_type(1.4), mp_type(1.5), true, tol, max_iter).first;
  154. mp_type x2 = x;
  155. double lim = 1e-65;
  156. if(fabs(x2 - root) < lim)
  157. {
  158. //
  159. // This is a problem area:
  160. // x2-root suffers cancellation error, so does digamma.
  161. // That gets compounded again when Remez calculates the error
  162. // function. This cludge seems to stop the worst of the problems:
  163. //
  164. static const mp_type a = boost::math::digamma(root - lim) / -lim;
  165. static const mp_type b = boost::math::digamma(root + lim) / lim;
  166. mp_type fract = (x2 - root + lim) / (2*lim);
  167. mp_type r = (1-fract) * a + fract * b;
  168. std::cout << "In root area: " << r;
  169. return r;
  170. }
  171. mp_type result = boost::math::digamma(x2) / (x2 - root);
  172. if(current_precision < 1000)
  173. set_working_precision(current_precision);
  174. return result;
  175. }
  176. case 11:
  177. // expm1:
  178. if(x == 0)
  179. {
  180. static mp_type lim = 1e-80;
  181. static mp_type a = boost::math::expm1(-lim);
  182. static mp_type b = boost::math::expm1(lim);
  183. static mp_type l = (b-a) / (2 * lim);
  184. return l;
  185. }
  186. return boost::math::expm1(x) / x;
  187. case 12:
  188. // demo, and test case:
  189. return exp(x);
  190. case 13:
  191. // K(k):
  192. {
  193. return boost::math::ellint_1(x);
  194. }
  195. case 14:
  196. // K(k)
  197. {
  198. return boost::math::ellint_1(1-x) / log(x);
  199. }
  200. case 15:
  201. // E(k)
  202. {
  203. // x = 1-k^2
  204. mp_type z = 1 - x * log(x);
  205. return boost::math::ellint_2(sqrt(1-x)) / z;
  206. }
  207. case 16:
  208. // Bessel I0(x) over [0,16]:
  209. {
  210. return boost::math::cyl_bessel_i(0, sqrt(x));
  211. }
  212. case 17:
  213. // Bessel I0(x) over [16,INF]
  214. {
  215. mp_type z = 1 / (mp_type(1)/16 - x);
  216. return boost::math::cyl_bessel_i(0, z) * sqrt(z) / exp(z);
  217. }
  218. case 18:
  219. // Zeta over [0, 1]
  220. {
  221. return boost::math::zeta(1 - x) * x - x;
  222. }
  223. case 19:
  224. // Zeta over [1, n]
  225. {
  226. return boost::math::zeta(x) - 1 / (x - 1);
  227. }
  228. case 20:
  229. // Zeta over [a, b] : a >> 1
  230. {
  231. return log(boost::math::zeta(x) - 1);
  232. }
  233. case 21:
  234. // expint[1] over [0,1]:
  235. {
  236. mp_type tiny = boost::lexical_cast<mp_type>("1e-5000");
  237. mp_type z = (x <= tiny) ? tiny : x;
  238. return boost::math::expint(1, z) - z + log(z);
  239. }
  240. case 22:
  241. // expint[1] over [1,N],
  242. // Note that x varies from [0,1]:
  243. {
  244. mp_type z = 1 / x;
  245. return boost::math::expint(1, z) * exp(z) * z;
  246. }
  247. case 23:
  248. // expin Ei over [0,R]
  249. {
  250. static const mp_type root =
  251. boost::lexical_cast<mp_type>("0.372507410781366634461991866580119133535689497771654051555657435242200120636201854384926049951548942392");
  252. mp_type z = x < (std::numeric_limits<long double>::min)() ? (std::numeric_limits<long double>::min)() : x;
  253. return (boost::math::expint(z) - log(z / root)) / (z - root);
  254. }
  255. case 24:
  256. // Expint Ei for large x:
  257. {
  258. static const mp_type root =
  259. boost::lexical_cast<mp_type>("0.372507410781366634461991866580119133535689497771654051555657435242200120636201854384926049951548942392");
  260. mp_type z = x < (std::numeric_limits<long double>::min)() ? (std::numeric_limits<long double>::max)() : mp_type(1 / x);
  261. return (boost::math::expint(z) - z) * z * exp(-z);
  262. //return (boost::math::expint(z) - log(z)) * z * exp(-z);
  263. }
  264. case 25:
  265. // Expint Ei for large x:
  266. {
  267. return (boost::math::expint(x) - x) * x * exp(-x);
  268. }
  269. case 26:
  270. {
  271. //
  272. // erf_inv in range [0, 0.5]
  273. //
  274. mp_type y = x;
  275. if(y == 0)
  276. y = boost::math::tools::epsilon<mp_type>() / 64;
  277. y = sqrt(y);
  278. return boost::math::erf_inv(y) / (y);
  279. }
  280. case 28:
  281. {
  282. // log1p over [-0.5,0.5]
  283. mp_type y = x;
  284. if(fabs(y) < 1e-100)
  285. y = (y == 0) ? 1e-100 : boost::math::sign(y) * 1e-100;
  286. return (boost::math::log1p(y) - y + y * y / 2) / (y);
  287. }
  288. case 29:
  289. {
  290. // cbrt over [0.5, 1]
  291. return boost::math::cbrt(x);
  292. }
  293. case 30:
  294. {
  295. // trigamma over [x,y]
  296. mp_type y = x;
  297. y = sqrt(y);
  298. return boost::math::trigamma(x) * (x * x);
  299. }
  300. case 31:
  301. {
  302. // trigamma over [x, INF]
  303. if(x == 0) return 1;
  304. mp_type y = (x == 0) ? (std::numeric_limits<double>::max)() / 2 : mp_type(1/x);
  305. return boost::math::trigamma(y) * y;
  306. }
  307. case 32:
  308. {
  309. // I0 over [N, INF]
  310. // Don't need to go past x = 1/1000 = 1e-3 for double, or
  311. // 1/15000 = 0.0006 for long double, start at 1/7.75=0.13
  312. mp_type arg = 1 / x;
  313. return sqrt(arg) * exp(-arg) * boost::math::cyl_bessel_i(0, arg);
  314. }
  315. case 33:
  316. {
  317. // I0 over [0, N]
  318. mp_type xx = sqrt(x) * 2;
  319. return (boost::math::cyl_bessel_i(0, xx) - 1) / x;
  320. }
  321. case 34:
  322. {
  323. // I1 over [0, N]
  324. mp_type xx = sqrt(x) * 2;
  325. return (boost::math::cyl_bessel_i(1, xx) * 2 / xx - 1 - x / 2) / (x * x);
  326. }
  327. case 35:
  328. {
  329. // I1 over [N, INF]
  330. mp_type xx = 1 / x;
  331. return boost::math::cyl_bessel_i(1, xx) * sqrt(xx) * exp(-xx);
  332. }
  333. case 36:
  334. {
  335. // K0 over [0, 1]
  336. mp_type xx = sqrt(x);
  337. return boost::math::cyl_bessel_k(0, xx) + log(xx) * boost::math::cyl_bessel_i(0, xx);
  338. }
  339. case 37:
  340. {
  341. // K0 over [1, INF]
  342. mp_type xx = 1 / x;
  343. return boost::math::cyl_bessel_k(0, xx) * exp(xx) * sqrt(xx);
  344. }
  345. case 38:
  346. {
  347. // K1 over [0, 1]
  348. mp_type xx = sqrt(x);
  349. return (boost::math::cyl_bessel_k(1, xx) - log(xx) * boost::math::cyl_bessel_i(1, xx) - 1 / xx) / xx;
  350. }
  351. case 39:
  352. {
  353. // K1 over [1, INF]
  354. mp_type xx = 1 / x;
  355. return boost::math::cyl_bessel_k(1, xx) * sqrt(xx) * exp(xx);
  356. }
  357. // Lambert W0
  358. case 40:
  359. return boost::math::lambert_w0(x);
  360. case 41:
  361. {
  362. if (x == 0)
  363. return 1;
  364. return boost::math::lambert_w0(x) / x;
  365. }
  366. case 42:
  367. {
  368. static const mp_type e1 = exp(mp_type(-1));
  369. return x / -boost::math::lambert_w0(-e1 + x);
  370. }
  371. case 43:
  372. {
  373. mp_type xx = 1 / x;
  374. return 1 / boost::math::lambert_w0(xx);
  375. }
  376. case 44:
  377. {
  378. mp_type ex = exp(x);
  379. return boost::math::lambert_w0(ex) - x;
  380. }
  381. }
  382. return 0;
  383. }
  384. void show_extra(
  385. const boost::math::tools::polynomial<mp_type>& n,
  386. const boost::math::tools::polynomial<mp_type>& d,
  387. const mp_type& x_offset,
  388. const mp_type& y_offset,
  389. int variant)
  390. {
  391. switch(variant)
  392. {
  393. default:
  394. // do nothing here...
  395. ;
  396. }
  397. }