bessel_derivative_data_from_bessel_ipps.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright (c) 2014 Anton Bikineev
  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. //
  6. // Computes test data for the derivatives of the
  7. // various bessel functions. v and x parameters are taken
  8. // from bessel_*_data.ipp files. Results of derivatives
  9. // are generated by the relations between the derivatives
  10. // and Bessel functions, which actual implementation
  11. // doesn't use. Results are printed to ~ 50 digits.
  12. //
  13. #include <fstream>
  14. #include <utility>
  15. #include <map>
  16. #include <iterator>
  17. #include <algorithm>
  18. #include <boost/multiprecision/mpfr.hpp>
  19. #include <boost/math/special_functions/bessel.hpp>
  20. template <class T>
  21. T bessel_j_derivative_bare(T v, T x)
  22. {
  23. return (v / x) * boost::math::cyl_bessel_j(v, x) - boost::math::cyl_bessel_j(v+1, x);
  24. }
  25. template <class T>
  26. T bessel_y_derivative_bare(T v, T x)
  27. {
  28. return (v / x) * boost::math::cyl_neumann(v, x) - boost::math::cyl_neumann(v+1, x);
  29. }
  30. template <class T>
  31. T bessel_i_derivative_bare(T v, T x)
  32. {
  33. return (v / x) * boost::math::cyl_bessel_i(v, x) + boost::math::cyl_bessel_i(v+1, x);
  34. }
  35. template <class T>
  36. T bessel_k_derivative_bare(T v, T x)
  37. {
  38. return (v / x) * boost::math::cyl_bessel_k(v, x) - boost::math::cyl_bessel_k(v+1, x);
  39. }
  40. template <class T>
  41. T sph_bessel_j_derivative_bare(T v, T x)
  42. {
  43. if((v < 0) || (floor(v) != v))
  44. throw std::domain_error("");
  45. if(v == 0)
  46. return -boost::math::sph_bessel(1, x);
  47. return boost::math::sph_bessel(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_bessel(itrunc(v), x);
  48. }
  49. template <class T>
  50. T sph_bessel_y_derivative_bare(T v, T x)
  51. {
  52. if((v < 0) || (floor(v) != v))
  53. throw std::domain_error("");
  54. if(v == 0)
  55. return -boost::math::sph_neumann(1, x);
  56. return boost::math::sph_neumann(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_neumann(itrunc(v), x);
  57. }
  58. using FloatType = boost::multiprecision::number<boost::multiprecision::mpfr_float_backend<200u> >;
  59. enum class BesselFamily: char
  60. {
  61. J = 0,
  62. Y,
  63. I,
  64. K,
  65. j,
  66. y
  67. };
  68. namespace
  69. {
  70. const unsigned kSignificand = 50u;
  71. const std::map<BesselFamily, std::vector<std::string> > kSourceFiles = {
  72. {BesselFamily::J, {"bessel_j_data.ipp", "bessel_j_int_data.ipp", "bessel_j_large_data.ipp"}},
  73. {BesselFamily::Y, {"bessel_y01_data.ipp", "bessel_yn_data.ipp", "bessel_yv_data.ipp"}},
  74. {BesselFamily::I, {"bessel_i_data.ipp", "bessel_i_int_data.ipp"}},
  75. {BesselFamily::K, {"bessel_k_data.ipp", "bessel_k_int_data.ipp"}},
  76. {BesselFamily::j, {"sph_bessel_data.ipp"}},
  77. {BesselFamily::y, {"sph_neumann_data.ipp"}}
  78. };
  79. FloatType (*fp)(FloatType, FloatType) = ::bessel_j_derivative_bare;
  80. std::string parseValue(std::string::iterator& iter)
  81. {
  82. using std::isdigit;
  83. auto value = std::string{};
  84. while (!isdigit(*iter) && *iter != '-')
  85. ++iter;
  86. while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+')
  87. {
  88. value.push_back(*iter);
  89. ++iter;
  90. }
  91. return value;
  92. }
  93. void replaceResultInLine(std::string& line)
  94. {
  95. using std::isdigit;
  96. auto iter = line.begin();
  97. // parse v and x values from line and convert them to FloatType
  98. auto v = FloatType{::parseValue(iter)};
  99. auto x = FloatType{::parseValue(iter)};
  100. auto result = fp(v, x).str(kSignificand);
  101. while (!isdigit(*iter) && *iter != '-')
  102. ++iter;
  103. const auto where_to_write = iter;
  104. while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+')
  105. line.erase(iter);
  106. line.insert(where_to_write, result.begin(), result.end());
  107. }
  108. void generateResultFile(const std::string& i_file, const std::string& o_file)
  109. {
  110. std::ifstream in{i_file.c_str()};
  111. std::ofstream out{o_file.c_str()};
  112. auto line = std::string{};
  113. while (!in.eof())
  114. {
  115. std::getline(in, line);
  116. if (__builtin_expect(line.find("SC_") != std::string::npos, 1))
  117. ::replaceResultInLine(line);
  118. out << line << std::endl;
  119. }
  120. }
  121. void processFiles(BesselFamily family)
  122. {
  123. const auto& family_files = kSourceFiles.find(family)->second;
  124. std::for_each(std::begin(family_files), std::end(family_files),
  125. [&](const std::string& src){
  126. auto new_file = src;
  127. const auto int_pos = new_file.find("int");
  128. const auto large_pos = new_file.find("large");
  129. const auto data_pos = new_file.find("data");
  130. const auto derivative_pos = (int_pos == std::string::npos ?
  131. (large_pos == std::string::npos ? data_pos : large_pos) :
  132. int_pos);
  133. new_file.insert(derivative_pos, "derivative_");
  134. ::generateResultFile(src, new_file);
  135. });
  136. }
  137. } // namespace
  138. int main(int argc, char*argv [])
  139. {
  140. auto functype = BesselFamily::J;
  141. auto letter = std::string{"J"};
  142. if(argc == 2)
  143. {
  144. if(std::strcmp(argv[1], "--Y") == 0)
  145. {
  146. functype = BesselFamily::Y;
  147. fp = ::bessel_y_derivative_bare;
  148. letter = "Y";
  149. }
  150. else if(std::strcmp(argv[1], "--I") == 0)
  151. {
  152. functype = BesselFamily::I;
  153. fp = ::bessel_i_derivative_bare;
  154. letter = "I";
  155. }
  156. else if(std::strcmp(argv[1], "--K") == 0)
  157. {
  158. functype = BesselFamily::K;
  159. fp = ::bessel_k_derivative_bare;
  160. letter = "K";
  161. }
  162. else if(std::strcmp(argv[1], "--j") == 0)
  163. {
  164. functype = BesselFamily::j;
  165. fp = ::sph_bessel_j_derivative_bare;
  166. letter = "j";
  167. }
  168. else if(std::strcmp(argv[1], "--y") == 0)
  169. {
  170. functype = BesselFamily::y;
  171. fp = ::sph_bessel_y_derivative_bare;
  172. letter = "y";
  173. }
  174. else
  175. BOOST_ASSERT(0);
  176. }
  177. ::processFiles(functype);
  178. return 0;
  179. }