plot_1d_errors.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. // Copyright John Maddock 2018.
  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 <map>
  6. #include <boost/config.hpp>
  7. #include <boost/multiprecision/cpp_bin_float.hpp>
  8. #ifdef BOOST_HAS_FLOAT128
  9. #include <boost/multiprecision/float128.hpp>
  10. #endif
  11. #include <boost/svg_plot/svg_2d_plot.hpp>
  12. template <class Real>
  13. Real interval_from_range(Real x)
  14. {
  15. BOOST_MATH_STD_USING
  16. Real l = floor(log10(x));
  17. l = pow(10, l);
  18. if (x / l < 2)
  19. l /= 10;
  20. return l;
  21. }
  22. std::string normalise_filename(std::string name)
  23. {
  24. for(std::string::size_type i = 0; i < name.size(); ++i)
  25. {
  26. if (!std::isalnum(name[i]))
  27. name[i] = '_';
  28. else
  29. name[i] = std::tolower(name[i]);
  30. }
  31. return name;
  32. }
  33. template <class F, class Real>
  34. void plot_errors_1d(F f, Real start, Real end, unsigned points, const char* function_name, Real max_y_scale = (std::numeric_limits<Real>::max)(), unsigned num_bins = 200)
  35. {
  36. BOOST_MATH_STD_USING
  37. std::cout << "Generating points for " << function_name << std::endl;
  38. Real pos = start;
  39. Real interval = (end - start) / points;
  40. std::map<Real, Real> points_upper, points_lower;
  41. Real max_distance(0), min_distance(0), max_error(0), max_error_location(0);
  42. constexpr unsigned limb_bits = (sizeof(boost::multiprecision::limb_type) * CHAR_BIT);
  43. constexpr unsigned mp_digits = (((std::numeric_limits<Real>::digits * 2) / limb_bits + ((std::numeric_limits<Real>::digits * 2) % limb_bits ? 1 : 0))) * limb_bits;
  44. typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<mp_digits, boost::multiprecision::backends::digit_base_2> > mp_type;
  45. while (pos <= end)
  46. {
  47. try
  48. {
  49. Real found_value = f(pos);
  50. Real exact_value = static_cast<Real>(f(mp_type(pos)));
  51. Real distance = boost::math::sign(found_value - exact_value) * boost::math::epsilon_difference(found_value, exact_value);
  52. Real bin = start + ((end - start) / num_bins) * boost::math::itrunc(num_bins * (pos - start) / (end - start));
  53. if (points_lower.find(bin) == points_lower.end())
  54. points_lower[bin] = 0;
  55. if (points_upper.find(bin) == points_upper.end())
  56. points_upper[bin] = 0;
  57. if (distance > 0)
  58. {
  59. if (points_upper[bin] < distance)
  60. points_upper[bin] = (std::min)(distance, max_y_scale);
  61. }
  62. else
  63. {
  64. if (points_lower[bin] > distance)
  65. points_lower[bin] = (std::max)(distance, -max_y_scale);
  66. }
  67. if (max_distance < distance)
  68. max_distance = (std::min)(distance, max_y_scale);
  69. if (min_distance > distance)
  70. min_distance = (std::max)(distance, -max_y_scale);
  71. if (fabs(distance) > max_error)
  72. {
  73. max_error = fabs(distance);
  74. max_error_location = pos;
  75. }
  76. pos += interval;
  77. }
  78. catch (const std::exception& e)
  79. {
  80. std::cout << "Found exception at point " << pos << " : " << e.what() << std::endl;
  81. pos += interval;
  82. }
  83. }
  84. std::cout << "Max error was " << std::setprecision(3) << max_error << " at location " << std::setprecision(std::numeric_limits<Real>::max_digits10) << max_error_location << std::endl;
  85. boost::svg::svg_2d_plot plot;
  86. Real x_start(start), x_end(end);
  87. if (end - start > 3)
  88. {
  89. x_start = floor(start);
  90. x_end = ceil(end);
  91. }
  92. if (min_distance == 0)
  93. min_distance = -1;
  94. if (max_distance == 0)
  95. max_distance = 1;
  96. plot.title(std::string("Errors in ") + function_name).x_range((double)x_start, (double)x_end).image_x_size(700).legend_border_color(boost::svg::lightgray).plot_border_color(boost::svg::lightgray).background_border_color(boost::svg::lightgray)
  97. .y_range((int)floor(min_distance), (int)ceil(max_distance)).x_label("x").y_major_interval((double)interval_from_range(max_distance) * 2).x_major_interval((double)interval_from_range(end - start)).legend_on(true).plot_window_on(true).legend_on(false);
  98. plot.plot(points_upper).stroke_color(boost::svg::green).fill_color(boost::svg::green).size(1).line_on(true).area_fill(boost::svg::green);
  99. plot.plot(points_lower).stroke_color(boost::svg::green).fill_color(boost::svg::green).size(1).line_on(true).area_fill(boost::svg::green);
  100. plot.write(normalise_filename(function_name) + ".svg");
  101. }
  102. #include <boost/math/special_functions.hpp>
  103. struct digamma_func
  104. {
  105. template <class T>
  106. T operator()(T x)
  107. {
  108. return boost::math::digamma(x);
  109. }
  110. };
  111. struct tgamma_func
  112. {
  113. template <class T>
  114. T operator()(T x)
  115. {
  116. return boost::math::tgamma(x);
  117. }
  118. };
  119. struct lgamma_func
  120. {
  121. template <class T>
  122. T operator()(T x)
  123. {
  124. return boost::math::lgamma(x);
  125. }
  126. };
  127. struct trigamma_func
  128. {
  129. template <class T>
  130. T operator()(T x)
  131. {
  132. return boost::math::tgamma(x);
  133. }
  134. };
  135. struct erf_func
  136. {
  137. template <class T>
  138. T operator()(T x)
  139. {
  140. return boost::math::erf(x);
  141. }
  142. };
  143. struct erfc_func
  144. {
  145. template <class T>
  146. T operator()(T x)
  147. {
  148. return boost::math::erfc(x);
  149. }
  150. };
  151. struct j0_func
  152. {
  153. template <class T>
  154. T operator()(T x)
  155. {
  156. return boost::math::cyl_bessel_j(0, x);
  157. }
  158. };
  159. struct j1_func
  160. {
  161. template <class T>
  162. T operator()(T x)
  163. {
  164. return boost::math::cyl_bessel_j(1, x);
  165. }
  166. };
  167. struct y0_func
  168. {
  169. template <class T>
  170. T operator()(T x)
  171. {
  172. return boost::math::cyl_neumann(0, x);
  173. }
  174. };
  175. struct y1_func
  176. {
  177. template <class T>
  178. T operator()(T x)
  179. {
  180. return boost::math::cyl_neumann(1, x);
  181. }
  182. };
  183. struct i0_func
  184. {
  185. template <class T>
  186. T operator()(T x)
  187. {
  188. return boost::math::cyl_bessel_i(0, x);
  189. }
  190. };
  191. struct i1_func
  192. {
  193. template <class T>
  194. T operator()(T x)
  195. {
  196. return boost::math::cyl_bessel_i(1, x);
  197. }
  198. };
  199. struct k0_func
  200. {
  201. template <class T>
  202. T operator()(T x)
  203. {
  204. return boost::math::cyl_bessel_k(0, x);
  205. }
  206. };
  207. struct k1_func
  208. {
  209. template <class T>
  210. T operator()(T x)
  211. {
  212. return boost::math::cyl_bessel_k(1, x);
  213. }
  214. };
  215. struct ai_func
  216. {
  217. template <class T>
  218. T operator()(T x)
  219. {
  220. return boost::math::airy_ai(x);
  221. }
  222. };
  223. struct aip_func
  224. {
  225. template <class T>
  226. T operator()(T x)
  227. {
  228. return boost::math::airy_ai_prime(x);
  229. }
  230. };
  231. struct bi_func
  232. {
  233. template <class T>
  234. T operator()(T x)
  235. {
  236. return boost::math::airy_bi(x);
  237. }
  238. };
  239. struct bip_func
  240. {
  241. template <class T>
  242. T operator()(T x)
  243. {
  244. return boost::math::airy_bi_prime(x);
  245. }
  246. };
  247. struct ellint_1_func
  248. {
  249. template <class T>
  250. T operator()(T x)
  251. {
  252. return boost::math::ellint_1(x);
  253. }
  254. };
  255. struct ellint_2_func
  256. {
  257. template <class T>
  258. T operator()(T x)
  259. {
  260. return boost::math::ellint_2(x);
  261. }
  262. };
  263. struct ellint_d_func
  264. {
  265. template <class T>
  266. T operator()(T x)
  267. {
  268. return boost::math::ellint_d(x);
  269. }
  270. };
  271. struct zeta_func
  272. {
  273. template <class T>
  274. T operator()(T x)
  275. {
  276. return boost::math::zeta(x);
  277. }
  278. };
  279. struct ei_func
  280. {
  281. template <class T>
  282. T operator()(T x)
  283. {
  284. return boost::math::expint(x);
  285. }
  286. };
  287. int main()
  288. {
  289. plot_errors_1d(digamma_func(), 1e-200, 10.0, 10000, "digamma, double");
  290. plot_errors_1d(tgamma_func(), 1e-200, 150.0, 10000, "tgamma, double");
  291. plot_errors_1d(lgamma_func(), 1e-200, 1000.0, 10000, "lgamma, double");
  292. plot_errors_1d(trigamma_func(), 1e-200, 10.0, 10000, "trigamma, double");
  293. plot_errors_1d(erf_func(), -5.0, 5.0, 10000, "erf, double");
  294. plot_errors_1d(erfc_func(), -5.0, 30.0, 10000, "erfc, double");
  295. plot_errors_1d(j0_func(), 0.0, 50.0, 10000, "j0, double", 50.0);
  296. plot_errors_1d(j1_func(), 0.0, 50.0, 10000, "j1, double", 50.0);
  297. plot_errors_1d(y0_func(), 1e-100, 50.0, 10000, "y0, double", 50.0);
  298. plot_errors_1d(y1_func(), 1e-100, 50.0, 10000, "y1, double", 50.0);
  299. plot_errors_1d(i0_func(), 0.0, 50.0, 10000, "i0, double");
  300. plot_errors_1d(i1_func(), 0.0, 50.0, 10000, "i1, double");
  301. plot_errors_1d(k0_func(), 1e-100, 50.0, 10000, "k0, double");
  302. plot_errors_1d(k1_func(), 1e-100, 50.0, 10000, "k1, double");
  303. plot_errors_1d(ai_func(), -20.0, 20.0, 10000, "Ai, double", 100.0);
  304. plot_errors_1d(bi_func(), -20.0, 20.0, 10000, "Bi, double", 100.0);
  305. plot_errors_1d(aip_func(), -20.0, 20.0, 10000, "Ai Prime, double", 100.0);
  306. plot_errors_1d(bip_func(), -20.0, 20.0, 10000, "Bi Prime, double", 100.0);
  307. plot_errors_1d(ellint_1_func(), -1.0, 1.0, 10000, "Elliptic Integral K, double");
  308. plot_errors_1d(ellint_2_func(), -1.0, 1.0, 10000, "Elliptic Integral E, double");
  309. plot_errors_1d(ellint_d_func(), -1.0, 1.0, 10000, "Elliptic Integral D, double");
  310. plot_errors_1d(zeta_func(), -20.0, 20.0, 10000, "Zeta, double");
  311. plot_errors_1d(ei_func(), -20.0, 20.0, 10000, "Exponential Integral Ei, double");
  312. #if LDBL_MANT_DIG == 64
  313. plot_errors_1d(digamma_func(), 1e-200L, 10.0L, 10000, "digamma, 80-bit long double");
  314. plot_errors_1d(tgamma_func(), 1e-200L, 150.0L, 10000, "tgamma, 80-bit long double");
  315. plot_errors_1d(lgamma_func(), 1e-200L, 1000.0L, 10000, "lgamma, 80-bit long double");
  316. plot_errors_1d(trigamma_func(), 1e-200L, 10.0L, 10000, "trigamma, 80-bit long double");
  317. plot_errors_1d(erf_func(), -5.0L, 5.0L, 10000, "erf, 80-bit long double");
  318. plot_errors_1d(erfc_func(), -5.0L, 120.0L, 10000, "erfc, 80-bit long double");
  319. plot_errors_1d(j0_func(), 0.0L, 50.0L, 10000, "j0, 80 bit long double", 50.0L);
  320. plot_errors_1d(j1_func(), 0.0L, 50.0L, 10000, "j1, 80 bit long double", 50.0L);
  321. plot_errors_1d(y0_func(), 1e-100L, 50.0L, 10000, "y0, 80 bit long double", 50.0L);
  322. plot_errors_1d(y1_func(), 1e-100L, 50.0L, 10000, "y1, 80 bit long double", 50.0L);
  323. plot_errors_1d(i0_func(), 0.0L, 50.0L, 10000, "i0, 80 bit long double");
  324. plot_errors_1d(i1_func(), 0.0L, 50.0L, 10000, "i1, 80 bit long double");
  325. plot_errors_1d(k0_func(), 1e-100L, 50.0L, 10000, "k0, 80 bit long double");
  326. plot_errors_1d(k1_func(), 1e-100L, 50.0L, 10000, "k1, 80 bit long double");
  327. plot_errors_1d(ai_func(), -20.0L, 20.0L, 10000, "Ai, 80 bit long double", 100.0L);
  328. plot_errors_1d(bi_func(), -20.0L, 20.0L, 10000, "Bi, 80 bit long double", 100.0L);
  329. plot_errors_1d(aip_func(), -20.0L, 20.0L, 10000, "Ai Prime, 80 bit long double", 100.0L);
  330. plot_errors_1d(bip_func(), -20.0L, 20.0L, 10000, "Bi Prime, 80 bit long double", 100.0L);
  331. plot_errors_1d(ellint_1_func(), -1.0L, 1.0L, 10000, "Elliptic Integral K, 80 bit long double");
  332. plot_errors_1d(ellint_2_func(), -1.0L, 1.0L, 10000, "Elliptic Integral E, 80 bit long double");
  333. plot_errors_1d(ellint_d_func(), -1.0L, 1.0L, 10000, "Elliptic Integral D, 80 bit long double");
  334. plot_errors_1d(zeta_func(), -20.0L, 20.0L, 10000, "Zeta, 80 bit long double");
  335. plot_errors_1d(ei_func(), -20.0L, 20.0L, 10000, "Exponential Integral Ei, 80 bit long double");
  336. #endif
  337. #ifdef BOOST_HAS_FLOAT128
  338. plot_errors_1d(digamma_func(), boost::multiprecision::float128(1e-200), boost::multiprecision::float128(10.0), 10000, "digamma, __float128");
  339. plot_errors_1d(tgamma_func(), boost::multiprecision::float128(1e-200), boost::multiprecision::float128(150.0), 10000, "tgamma, __float128");
  340. plot_errors_1d(lgamma_func(), boost::multiprecision::float128(1e-200), boost::multiprecision::float128(1000.0), 10000, "lgamma, __float128");
  341. plot_errors_1d(trigamma_func(), boost::multiprecision::float128(1e-200), boost::multiprecision::float128(10.0), 10000, "trigamma, __float128");
  342. plot_errors_1d(erf_func(), -boost::multiprecision::float128(5.0), boost::multiprecision::float128(5.0), 10000, "erf, __float128");
  343. plot_errors_1d(erfc_func(), -boost::multiprecision::float128(5.0), boost::multiprecision::float128(120.0), 10000, "erfc, __float128");
  344. plot_errors_1d(j0_func(), boost::multiprecision::float128(0.0), boost::multiprecision::float128(50.0), 10000, "j0, __float128", boost::multiprecision::float128(50.0));
  345. plot_errors_1d(j1_func(), boost::multiprecision::float128(0.0), boost::multiprecision::float128(50.0), 10000, "j1, __float128", boost::multiprecision::float128(50.0));
  346. plot_errors_1d(y0_func(), boost::multiprecision::float128(1e-100), boost::multiprecision::float128(50.0), 10000, "y0, __float128", boost::multiprecision::float128(50.0));
  347. plot_errors_1d(y1_func(), boost::multiprecision::float128(1e-100), boost::multiprecision::float128(50.0), 10000, "y1, __float128", boost::multiprecision::float128(50.0));
  348. plot_errors_1d(i0_func(), boost::multiprecision::float128(0.0), boost::multiprecision::float128(50.0), 10000, "i0, __float128");
  349. plot_errors_1d(i1_func(), boost::multiprecision::float128(0.0), boost::multiprecision::float128(50.0), 10000, "i1, __float128");
  350. plot_errors_1d(k0_func(), boost::multiprecision::float128(1e-100), boost::multiprecision::float128(50.0), 10000, "k0, __float128");
  351. plot_errors_1d(k1_func(), boost::multiprecision::float128(1e-100), boost::multiprecision::float128(50.0), 10000, "k1, __float128");
  352. plot_errors_1d(ai_func(), -boost::multiprecision::float128(20.0), boost::multiprecision::float128(20.0), 10000, "Ai, __float128", boost::multiprecision::float128(100.0));
  353. plot_errors_1d(bi_func(), -boost::multiprecision::float128(20.0), boost::multiprecision::float128(20.0), 10000, "Bi, __float128", boost::multiprecision::float128(100.0));
  354. plot_errors_1d(aip_func(), -boost::multiprecision::float128(20.0), boost::multiprecision::float128(20.0), 10000, "Ai Prime, __float128", boost::multiprecision::float128(100.0));
  355. plot_errors_1d(bip_func(), -boost::multiprecision::float128(20.0), boost::multiprecision::float128(20.0), 10000, "Bi Prime, __float128", boost::multiprecision::float128(100.0));
  356. plot_errors_1d(ellint_1_func(), -boost::multiprecision::float128(1.0), boost::multiprecision::float128(1.0), 10000, "Elliptic Integral K, __float128");
  357. plot_errors_1d(ellint_2_func(), -boost::multiprecision::float128(1.0), boost::multiprecision::float128(1.0), 10000, "Elliptic Integral E, __float128");
  358. plot_errors_1d(ellint_d_func(), -boost::multiprecision::float128(1.0), boost::multiprecision::float128(1.0), 10000, "Elliptic Integral D, __float128");
  359. plot_errors_1d(zeta_func(), -boost::multiprecision::float128(20.0), boost::multiprecision::float128(20.0), 10000, "Zeta, __float128");
  360. plot_errors_1d(ei_func(), -boost::multiprecision::float128(20.0), boost::multiprecision::float128(20.0), 10000, "Exponential Integral Ei, __float128");
  361. #endif
  362. return 0;
  363. }