214 lines
5.7 KiB
C++
214 lines
5.7 KiB
C++
// 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 <fstream>
|
|
#include <utility>
|
|
#include <map>
|
|
#include <iterator>
|
|
#include <algorithm>
|
|
|
|
#include <boost/multiprecision/mpfr.hpp>
|
|
|
|
#include <boost/math/special_functions/bessel.hpp>
|
|
|
|
template <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
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<boost::multiprecision::mpfr_float_backend<200u> >;
|
|
|
|
enum class BesselFamily: char
|
|
{
|
|
J = 0,
|
|
Y,
|
|
I,
|
|
K,
|
|
j,
|
|
y
|
|
};
|
|
|
|
namespace
|
|
{
|
|
|
|
const unsigned kSignificand = 50u;
|
|
|
|
const std::map<BesselFamily, std::vector<std::string> > 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;
|
|
}
|