// Copyright (c) 2014 Anton Bikineev // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Computes test data for the derivatives of the // various bessel functions. v and x parameters are taken // from bessel_*_data.ipp files. Results of derivatives // are generated by the relations between the derivatives // and Bessel functions, which actual implementation // doesn't use. Results are printed to ~ 50 digits. // #include #include #include #include #include #include #include template T bessel_j_derivative_bare(T v, T x) { return (v / x) * boost::math::cyl_bessel_j(v, x) - boost::math::cyl_bessel_j(v+1, x); } template T bessel_y_derivative_bare(T v, T x) { return (v / x) * boost::math::cyl_neumann(v, x) - boost::math::cyl_neumann(v+1, x); } template T bessel_i_derivative_bare(T v, T x) { return (v / x) * boost::math::cyl_bessel_i(v, x) + boost::math::cyl_bessel_i(v+1, x); } template T bessel_k_derivative_bare(T v, T x) { return (v / x) * boost::math::cyl_bessel_k(v, x) - boost::math::cyl_bessel_k(v+1, x); } template T sph_bessel_j_derivative_bare(T v, T x) { if((v < 0) || (floor(v) != v)) throw std::domain_error(""); if(v == 0) return -boost::math::sph_bessel(1, x); return boost::math::sph_bessel(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_bessel(itrunc(v), x); } template T sph_bessel_y_derivative_bare(T v, T x) { if((v < 0) || (floor(v) != v)) throw std::domain_error(""); if(v == 0) return -boost::math::sph_neumann(1, x); return boost::math::sph_neumann(itrunc(v-1), x) - ((v + 1) / x) * boost::math::sph_neumann(itrunc(v), x); } using FloatType = boost::multiprecision::number >; enum class BesselFamily: char { J = 0, Y, I, K, j, y }; namespace { const unsigned kSignificand = 50u; const std::map > kSourceFiles = { {BesselFamily::J, {"bessel_j_data.ipp", "bessel_j_int_data.ipp", "bessel_j_large_data.ipp"}}, {BesselFamily::Y, {"bessel_y01_data.ipp", "bessel_yn_data.ipp", "bessel_yv_data.ipp"}}, {BesselFamily::I, {"bessel_i_data.ipp", "bessel_i_int_data.ipp"}}, {BesselFamily::K, {"bessel_k_data.ipp", "bessel_k_int_data.ipp"}}, {BesselFamily::j, {"sph_bessel_data.ipp"}}, {BesselFamily::y, {"sph_neumann_data.ipp"}} }; FloatType (*fp)(FloatType, FloatType) = ::bessel_j_derivative_bare; std::string parseValue(std::string::iterator& iter) { using std::isdigit; auto value = std::string{}; while (!isdigit(*iter) && *iter != '-') ++iter; while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+') { value.push_back(*iter); ++iter; } return value; } void replaceResultInLine(std::string& line) { using std::isdigit; auto iter = line.begin(); // parse v and x values from line and convert them to FloatType auto v = FloatType{::parseValue(iter)}; auto x = FloatType{::parseValue(iter)}; auto result = fp(v, x).str(kSignificand); while (!isdigit(*iter) && *iter != '-') ++iter; const auto where_to_write = iter; while (isdigit(*iter) || *iter == '.' || *iter == 'e' || *iter == '-' || *iter == '+') line.erase(iter); line.insert(where_to_write, result.begin(), result.end()); } void generateResultFile(const std::string& i_file, const std::string& o_file) { std::ifstream in{i_file.c_str()}; std::ofstream out{o_file.c_str()}; auto line = std::string{}; while (!in.eof()) { std::getline(in, line); if (__builtin_expect(line.find("SC_") != std::string::npos, 1)) ::replaceResultInLine(line); out << line << std::endl; } } void processFiles(BesselFamily family) { const auto& family_files = kSourceFiles.find(family)->second; std::for_each(std::begin(family_files), std::end(family_files), [&](const std::string& src){ auto new_file = src; const auto int_pos = new_file.find("int"); const auto large_pos = new_file.find("large"); const auto data_pos = new_file.find("data"); const auto derivative_pos = (int_pos == std::string::npos ? (large_pos == std::string::npos ? data_pos : large_pos) : int_pos); new_file.insert(derivative_pos, "derivative_"); ::generateResultFile(src, new_file); }); } } // namespace int main(int argc, char*argv []) { auto functype = BesselFamily::J; auto letter = std::string{"J"}; if(argc == 2) { if(std::strcmp(argv[1], "--Y") == 0) { functype = BesselFamily::Y; fp = ::bessel_y_derivative_bare; letter = "Y"; } else if(std::strcmp(argv[1], "--I") == 0) { functype = BesselFamily::I; fp = ::bessel_i_derivative_bare; letter = "I"; } else if(std::strcmp(argv[1], "--K") == 0) { functype = BesselFamily::K; fp = ::bessel_k_derivative_bare; letter = "K"; } else if(std::strcmp(argv[1], "--j") == 0) { functype = BesselFamily::j; fp = ::sph_bessel_j_derivative_bare; letter = "j"; } else if(std::strcmp(argv[1], "--y") == 0) { functype = BesselFamily::y; fp = ::sph_bessel_y_derivative_bare; letter = "y"; } else BOOST_ASSERT(0); } ::processFiles(functype); return 0; }