test_toms748_solve.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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. #include <pch.hpp>
  6. #define BOOST_TEST_MAIN
  7. #include <boost/test/unit_test.hpp>
  8. #include <boost/test/tools/floating_point_comparison.hpp>
  9. #include <boost/math/tools/toms748_solve.hpp>
  10. #include <boost/math/special_functions/gamma.hpp>
  11. #include <boost/math/special_functions/beta.hpp>
  12. #include <iostream>
  13. #include <iomanip>
  14. //
  15. // Test functor implements the same test cases as used by
  16. // "Algorithm 748: Enclosing Zeros of Continuous Functions"
  17. // by G.E. Alefeld, F.A. Potra and Yixun Shi.
  18. //
  19. // Plus two more: one for inverting the incomplete gamma,
  20. // and one for inverting the incomplete beta.
  21. //
  22. template <class T>
  23. struct toms748tester
  24. {
  25. toms748tester(unsigned i) : k(i), ip(0), a(0), b(0){}
  26. toms748tester(unsigned i, int ip_) : k(i), ip(ip_), a(0), b(0){}
  27. toms748tester(unsigned i, T a_, T b_) : k(i), ip(0), a(a_), b(b_){}
  28. static unsigned total_calls()
  29. {
  30. return invocations;
  31. }
  32. static void reset()
  33. {
  34. invocations = 0;
  35. }
  36. T operator()(T x)
  37. {
  38. using namespace std;
  39. ++invocations;
  40. switch(k)
  41. {
  42. case 1:
  43. return sin(x) - x / 2;
  44. case 2:
  45. {
  46. T r = 0;
  47. for(int i = 1; i <= 20; ++i)
  48. {
  49. T p = (2 * i - 5);
  50. T q = x - i * i;
  51. r += p * p / (q * q * q);
  52. }
  53. r *= -2;
  54. return r;
  55. }
  56. case 3:
  57. return a * x * exp(b * x);
  58. case 4:
  59. return pow(x, b) - a;
  60. case 5:
  61. return sin(x) - 0.5;
  62. case 6:
  63. return 2 * x * exp(-T(ip)) - 2 * exp(-ip * x) + 1;
  64. case 7:
  65. return (1 + (1 - ip) * (1 - ip)) * x - (1 - ip * x) * (1 - ip * x);
  66. case 8:
  67. return x * x - pow(1 - x, a);
  68. case 9:
  69. return (1 + (1 - ip) * (1 - ip) * (1 - ip) * (1 - ip)) * x - (1 - ip * x) * (1 - ip * x) * (1 - ip * x) * (1 - ip * x);
  70. case 10:
  71. return exp(-ip * x) * (x - 1) + pow(x, T(ip));
  72. case 11:
  73. return (ip * x - 1) / ((ip - 1) * x);
  74. case 12:
  75. return pow(x, T(1)/ip) - pow(T(ip), T(1)/ip);
  76. case 13:
  77. return x == 0 ? 0 : x * exp(-1 / (x * x));
  78. case 14:
  79. return x >= 0 ? (T(ip)/20) * (x / 1.5f + sin(x) - 1) : -T(ip)/20;
  80. case 15:
  81. {
  82. T d = 2e-3f / (1+ip);
  83. if(x > d)
  84. return exp(1.0) - 1.859;
  85. else if(x > 0)
  86. return exp((ip+1)*x*1000 / 2) - 1.859;
  87. return -0.859f;
  88. }
  89. case 16:
  90. {
  91. return boost::math::gamma_q(x, a) - b;
  92. }
  93. case 17:
  94. return boost::math::ibeta(x, a, 0.5) - b;
  95. }
  96. return 0;
  97. }
  98. private:
  99. int k; // index of problem.
  100. int ip; // integer parameter
  101. T a, b; // real parameter
  102. static unsigned invocations;
  103. };
  104. template <class T>
  105. unsigned toms748tester<T>::invocations = 0;
  106. boost::uintmax_t total = 0;
  107. boost::uintmax_t invocations = 0;
  108. template <class T>
  109. void run_test(T a, T b, int id)
  110. {
  111. boost::uintmax_t c = 1000;
  112. std::pair<double, double> r = toms748_solve(toms748tester<double>(id),
  113. a,
  114. b,
  115. boost::math::tools::eps_tolerance<double>(std::numeric_limits<double>::digits),
  116. c);
  117. BOOST_CHECK_EQUAL(c, toms748tester<double>::total_calls());
  118. total += c;
  119. invocations += toms748tester<double>::total_calls();
  120. std::cout << "Function " << id << "\nresult={" << r.first << ", " << r.second << "} total calls=" << toms748tester<double>::total_calls() << "\n\n";
  121. toms748tester<double>::reset();
  122. }
  123. template <class T>
  124. void run_test(T a, T b, int id, int p)
  125. {
  126. boost::uintmax_t c = 1000;
  127. std::pair<double, double> r = toms748_solve(toms748tester<double>(id, p),
  128. a,
  129. b,
  130. boost::math::tools::eps_tolerance<double>(std::numeric_limits<double>::digits),
  131. c);
  132. BOOST_CHECK_EQUAL(c, toms748tester<double>::total_calls());
  133. total += c;
  134. invocations += toms748tester<double>::total_calls();
  135. std::cout << "Function " << id << "\nresult={" << r.first << ", " << r.second << "} total calls=" << toms748tester<double>::total_calls() << "\n\n";
  136. toms748tester<double>::reset();
  137. }
  138. template <class T>
  139. void run_test(T a, T b, int id, T p1, T p2)
  140. {
  141. boost::uintmax_t c = 1000;
  142. std::pair<double, double> r = toms748_solve(toms748tester<double>(id, p1, p2),
  143. a,
  144. b,
  145. boost::math::tools::eps_tolerance<double>(std::numeric_limits<double>::digits),
  146. c);
  147. BOOST_CHECK_EQUAL(c, toms748tester<double>::total_calls());
  148. total += c;
  149. invocations += toms748tester<double>::total_calls();
  150. std::cout << "Function " << id << "\n Result={" << r.first << ", " << r.second << "} total calls=" << toms748tester<double>::total_calls() << "\n\n";
  151. toms748tester<double>::reset();
  152. }
  153. BOOST_AUTO_TEST_CASE( test_main )
  154. {
  155. std::cout << std::setprecision(18);
  156. run_test(3.14/2, 3.14, 1);
  157. for(int i = 1; i <= 10; i += 1)
  158. {
  159. run_test(i*i + 1e-9, (i+1)*(i+1) - 1e-9, 2);
  160. }
  161. run_test(-9.0, 31.0, 3, -40.0, -1.0);
  162. run_test(-9.0, 31.0, 3, -100.0, -2.0);
  163. run_test(-9.0, 31.0, 3, -200.0, -3.0);
  164. for(int n = 4; n <= 12; n += 2)
  165. {
  166. run_test(0.0, 5.0, 4, 0.2, double(n));
  167. }
  168. for(int n = 4; n <= 12; n += 2)
  169. {
  170. run_test(0.0, 5.0, 4, 1.0, double(n));
  171. }
  172. for(int n = 8; n <= 14; n += 2)
  173. {
  174. run_test(-0.95, 4.05, 4, 1.0, double(n));
  175. }
  176. run_test(0.0, 1.5, 5);
  177. for(int n = 1; n <= 5; ++n)
  178. {
  179. run_test(0.0, 1.0, 6, n);
  180. }
  181. for(int n = 20; n <= 100; n += 20)
  182. {
  183. run_test(0.0, 1.0, 6, n);
  184. }
  185. run_test(0.0, 1.0, 7, 5);
  186. run_test(0.0, 1.0, 7, 10);
  187. run_test(0.0, 1.0, 7, 20);
  188. run_test(0.0, 1.0, 8, 2);
  189. run_test(0.0, 1.0, 8, 5);
  190. run_test(0.0, 1.0, 8, 10);
  191. run_test(0.0, 1.0, 8, 15);
  192. run_test(0.0, 1.0, 8, 20);
  193. run_test(0.0, 1.0, 9, 1);
  194. run_test(0.0, 1.0, 9, 2);
  195. run_test(0.0, 1.0, 9, 4);
  196. run_test(0.0, 1.0, 9, 5);
  197. run_test(0.0, 1.0, 9, 8);
  198. run_test(0.0, 1.0, 9, 15);
  199. run_test(0.0, 1.0, 9, 20);
  200. run_test(0.0, 1.0, 10, 1);
  201. run_test(0.0, 1.0, 10, 5);
  202. run_test(0.0, 1.0, 10, 10);
  203. run_test(0.0, 1.0, 10, 15);
  204. run_test(0.0, 1.0, 10, 20);
  205. run_test(0.01, 1.0, 11, 2);
  206. run_test(0.01, 1.0, 11, 5);
  207. run_test(0.01, 1.0, 11, 15);
  208. run_test(0.01, 1.0, 11, 20);
  209. for(int n = 2; n <= 6; ++n)
  210. run_test(1.0, 100.0, 12, n);
  211. for(int n = 7; n <= 33; n+=2)
  212. run_test(1.0, 100.0, 12, n);
  213. run_test(-1.0, 4.0, 13);
  214. for(int n = 1; n <= 40; ++n)
  215. run_test(-1e4, 3.14/2, 14, n);
  216. for(int n = 20; n <= 40; ++n)
  217. run_test(-1e4, 1e-4, 15, n);
  218. for(int n = 100; n <= 1000; n+=100)
  219. run_test(-1e4, 1e-4, 15, n);
  220. std::cout << "Total iterations consumed = " << total << std::endl;
  221. std::cout << "Total function invocations consumed = " << invocations << std::endl << std::endl;
  222. BOOST_CHECK(invocations < 3150);
  223. std::cout << std::setprecision(18);
  224. for(int n = 5; n <= 100; n += 10)
  225. run_test(sqrt(double(n)), double(n+1), 16, (double)n, 0.4);
  226. for(int n = 5; n <= 100; n += 10)
  227. run_test(double(n / 2), double(2*n), 17, (double)n, 0.4);
  228. for(int n = 4; n <= 12; n += 2)
  229. {
  230. boost::uintmax_t c = 1000;
  231. std::pair<double, double> r = bracket_and_solve_root(toms748tester<double>(4, 0.2, double(n)),
  232. 2.0,
  233. 2.0,
  234. true,
  235. boost::math::tools::eps_tolerance<double>(std::numeric_limits<double>::digits),
  236. c);
  237. std::cout << std::setprecision(18);
  238. std::cout << "Function " << 4 << "\n Result={" << r.first << ", " << r.second << "} total calls=" << toms748tester<double>::total_calls() << "\n\n";
  239. toms748tester<double>::reset();
  240. BOOST_CHECK(c < 20);
  241. }
  242. }