lambert_w_errors_graph.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright Paul A. Bristow 2017, 2018
  2. // Copyright John Z. Maddock 2017
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or
  5. // copy at http ://www.boost.org/LICENSE_1_0.txt).
  6. /*! \brief Graph showing differences of Lambert W function double from nearest representable values.
  7. \details
  8. */
  9. #include <boost/math/special_functions/lambert_w.hpp>
  10. using boost::math::lambert_w0;
  11. using boost::math::lambert_wm1;
  12. #include <boost/math/special_functions.hpp>
  13. using boost::math::isfinite;
  14. #include <boost/svg_plot/svg_2d_plot.hpp>
  15. using namespace boost::svg;
  16. // For higher precision computation of Lambert W.
  17. #include <boost/multiprecision/cpp_bin_float.hpp>
  18. #include <boost/math/special_functions/next.hpp> // For float_distance.
  19. using boost::math::float_distance;
  20. #include <iostream>
  21. // using std::cout;
  22. // using std::endl;
  23. #include <exception>
  24. #include <stdexcept>
  25. #include <string>
  26. #include <array>
  27. #include <vector>
  28. #include <utility>
  29. using std::pair;
  30. #include <map>
  31. using std::map;
  32. #include <set>
  33. using std::multiset;
  34. #include <limits>
  35. using std::numeric_limits;
  36. #include <cmath> // exp
  37. /*!
  38. */
  39. int main()
  40. {
  41. try
  42. {
  43. std::cout << "Lambert W errors graph." << std::endl;
  44. using boost::multiprecision::cpp_bin_float_50;
  45. using boost::multiprecision::cpp_bin_float_quad;
  46. typedef cpp_bin_float_quad HPT; // High precision type.
  47. using boost::math::float_distance;
  48. using boost::math::policies::precision;
  49. using boost::math::policies::digits10;
  50. using boost::math::policies::digits2;
  51. using boost::math::policies::policy;
  52. std::cout.precision(std::numeric_limits<double>::max_digits10);
  53. //[lambert_w_graph_1
  54. //] [/lambert_w_graph_1]
  55. {
  56. std::map<const double, double> w0s; // Lambert W0 branch values, default double precision, digits2 = 53.
  57. std::map<const double, double> w0s_50; // Lambert W0 branch values digits2 = 50.
  58. int max_distance = 0;
  59. int total_distance = 0;
  60. int count = 0;
  61. const int bits = 7;
  62. double min_z = -0.367879; // Close to singularity at -0.3678794411714423215955237701614608727 -exp(-1)
  63. //double min_z = 0.06; // Above 0.05 switch point.
  64. double max_z = 99.99;
  65. double step_z = 0.05;
  66. for (HPT z = min_z; z < max_z; z += step_z)
  67. {
  68. double zd = static_cast<double>(z);
  69. double w0d = lambert_w0(zd); // double result from same default.
  70. HPT w0_best = lambert_w0<HPT>(z);
  71. double w0_best_d = static_cast<double>(w0_best); // reference result.
  72. // w0s[zd] = (w0d - w0_best_d); // absolute difference.
  73. // w0s[z] = 100 * (w0 - w0_best) / w0_best; // difference relative % .
  74. w0s[zd] = float_distance<double>(w0d, w0_best_d); // difference in bits.
  75. double fd = float_distance<double>(w0d, w0_best_d);
  76. int distance = static_cast<int>(fd);
  77. int abs_distance = abs(distance);
  78. // std::cout << count << " " << zd << " " << w0d << " " << w0_best_d
  79. // << ", Difference = " << w0d - w0_best_d << ", % = " << (w0d - w0_best_d) / w0d << ", Distance = " << distance << std::endl;
  80. total_distance += abs_distance;
  81. if (abs_distance > max_distance)
  82. {
  83. max_distance = abs_distance;
  84. }
  85. count++;
  86. } // for z
  87. std::cout << "points " << count << std::endl;
  88. std::cout.precision(3);
  89. std::cout << "max distance " << max_distance << ", total distances = " << total_distance
  90. << ", mean distance " << (float)total_distance / count << std::endl;
  91. typedef std::map<const double, double>::const_iterator Map_Iterator;
  92. /* for (std::map<const double, double>::const_iterator it = w0s.begin(); it != w0s.end(); ++it)
  93. {
  94. std::cout << " " << *(it) << "\n";
  95. }
  96. */
  97. svg_2d_plot data_plot_0; // <-0.368, -46> <-0.358, -4> <-0.348, 1>...
  98. data_plot_0.title("Lambert W0 function differences from 'best' for double.")
  99. .title_font_size(11)
  100. .x_size(400)
  101. .y_size(200)
  102. .legend_on(false)
  103. //.legend_font_weight(1)
  104. .x_label("z")
  105. .y_label("W0 difference (bits)")
  106. //.x_label_on(true)
  107. //.y_label_on(true)
  108. //.xy_values_on(false)
  109. .x_range(-1, 100.)
  110. .y_range(-4., +4.)
  111. .x_major_interval(10.)
  112. .y_major_interval(2.)
  113. .x_major_grid_on(true)
  114. .y_major_grid_on(true)
  115. .x_label_font_size(9)
  116. .y_label_font_size(9)
  117. //.x_values_on(true)
  118. //.y_values_on(true)
  119. .y_values_rotation(horizontal)
  120. //.plot_window_on(true)
  121. .x_values_precision(3)
  122. .y_values_precision(3)
  123. .coord_precision(3) // Needed to avoid stepping on curves.
  124. //.coord_precision(4) // Needed to avoid stepping on curves.
  125. .copyright_holder("Paul A. Bristow")
  126. .copyright_date("2018")
  127. //.background_border_color(black);
  128. ;
  129. data_plot_0.plot(w0s, "W0 branch").line_color(red).shape(none).line_on(true).bezier_on(false).line_width(0.2);
  130. //data_plot.plot(wm1s, "W-1 branch").line_color(blue).shape(none).line_on(true).bezier_on(false).line_width(1);
  131. data_plot_0.write("./lambert_w0_errors_graph");
  132. } // end W0 branch plot.
  133. { // Repeat for Lambert W-1 branch.
  134. std::map<const double, double> wm1s; // Lambert W-1 branch values.
  135. std::map<const double, double> wm1s_50; // Lambert Wm1 branch values digits2 = 50.
  136. int max_distance = 0;
  137. int total_distance = 0;
  138. int count = 0;
  139. const int bits = 7;
  140. double min_z = -0.367879; // Close to singularity at -0.3678794411714423215955237701614608727 -exp(-1)
  141. //double min_z = 0.06; // Above 0.05 switch point.
  142. double max_z = -0.0001;
  143. double step_z = 0.001;
  144. for (HPT z = min_z; z < max_z; z += step_z)
  145. {
  146. if (z > max_z)
  147. {
  148. break;
  149. }
  150. double zd = static_cast<double>(z);
  151. double wm1d = lambert_wm1(zd); // double result from same default.
  152. HPT wm1_best = lambert_wm1<HPT>(z);
  153. double wm1_best_d = static_cast<double>(wm1_best); // reference result.
  154. // wm1s[zd] = (wm1d - wm1_best_d); // absolute difference.
  155. // wm1s[z] = 100 * (wm1 - wm1_best) / wm1_best; // difference relative % .
  156. wm1s[zd] = float_distance<double>(wm1d, wm1_best_d); // difference in bits.
  157. double fd = float_distance<double>(wm1d, wm1_best_d);
  158. int distance = static_cast<int>(fd);
  159. int abs_distance = abs(distance);
  160. //std::cout << count << " " << zd << " " << wm1d << " " << wm1_best_d
  161. // << ", Difference = " << wm1d - wm1_best_d << ", % = " << (wm1d - wm1_best_d) / wm1d << ", Distance = " << distance << std::endl;
  162. total_distance += abs_distance;
  163. if (abs_distance > max_distance)
  164. {
  165. max_distance = abs_distance;
  166. }
  167. count++;
  168. } // for z
  169. std::cout << "points " << count << std::endl;
  170. std::cout.precision(3);
  171. std::cout << "max distance " << max_distance << ", total distances = " << total_distance
  172. << ", mean distance " << (float)total_distance / count << std::endl;
  173. typedef std::map<const double, double>::const_iterator Map_Iterator;
  174. /* for (std::map<const double, double>::const_iterator it = wm1s.begin(); it != wm1s.end(); ++it)
  175. {
  176. std::cout << " " << *(it) << "\n";
  177. }
  178. */
  179. svg_2d_plot data_plot_m1; // <-0.368, -46> <-0.358, -4> <-0.348, 1>...
  180. data_plot_m1.title("Lambert W-1 function differences from 'best' for double.")
  181. .title_font_size(11)
  182. .x_size(400)
  183. .y_size(200)
  184. .legend_on(false)
  185. //.legend_font_weight(1)
  186. .x_label("z")
  187. .y_label("W-1 difference (bits)")
  188. .x_range(-0.39, +0.0001)
  189. .y_range(-4., +4.)
  190. .x_major_interval(0.1)
  191. .y_major_interval(2.)
  192. .x_major_grid_on(true)
  193. .y_major_grid_on(true)
  194. .x_label_font_size(9)
  195. .y_label_font_size(9)
  196. //.x_values_on(true)
  197. //.y_values_on(true)
  198. .y_values_rotation(horizontal)
  199. //.plot_window_on(true)
  200. .x_values_precision(3)
  201. .y_values_precision(3)
  202. .coord_precision(3) // Needed to avoid stepping on curves.
  203. //.coord_precision(4) // Needed to avoid stepping on curves.
  204. .copyright_holder("Paul A. Bristow")
  205. .copyright_date("2018")
  206. //.background_border_color(black);
  207. ;
  208. data_plot_m1.plot(wm1s, "W-1 branch").line_color(darkblue).shape(none).line_on(true).bezier_on(false).line_width(0.2);
  209. data_plot_m1.write("./lambert_wm1_errors_graph");
  210. }
  211. }
  212. catch (std::exception& ex)
  213. {
  214. std::cout << ex.what() << std::endl;
  215. }
  216. } // int main()
  217. /*
  218. //[lambert_w_errors_graph_1_output
  219. Lambert W errors graph.
  220. points 2008
  221. max distance 46, total distances = 717, mean distance 0.357
  222. points 368
  223. max distance 23, total distances = 329, mean distance 0.894
  224. //] [/lambert_w_errors_graph_1_output]
  225. */