File indexing completed on 2025-01-18 09:40:41
0001
0002
0003
0004
0005
0006 #ifndef BOOST_MATH_TOOLS_RECURRENCE_HPP_
0007 #define BOOST_MATH_TOOLS_RECURRENCE_HPP_
0008
0009 #include <type_traits>
0010 #include <tuple>
0011 #include <utility>
0012 #include <boost/math/tools/config.hpp>
0013 #include <boost/math/tools/precision.hpp>
0014 #include <boost/math/tools/tuple.hpp>
0015 #include <boost/math/tools/fraction.hpp>
0016 #include <boost/math/tools/cxx03_warn.hpp>
0017 #include <boost/math/tools/assert.hpp>
0018
0019 namespace boost {
0020 namespace math {
0021 namespace tools {
0022 namespace detail{
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 template <class Recurrence>
0034 struct function_ratio_from_backwards_recurrence_fraction
0035 {
0036 typedef typename std::remove_reference<decltype(std::get<0>(std::declval<Recurrence&>()(0)))>::type value_type;
0037 typedef std::pair<value_type, value_type> result_type;
0038 function_ratio_from_backwards_recurrence_fraction(const Recurrence& r) : r(r), k(0) {}
0039
0040 result_type operator()()
0041 {
0042 value_type a, b, c;
0043 std::tie(a, b, c) = r(k);
0044 ++k;
0045
0046
0047 value_type bn = a / c;
0048 value_type an = b / c;
0049 return result_type(-bn, an);
0050 }
0051
0052 private:
0053 function_ratio_from_backwards_recurrence_fraction operator=(const function_ratio_from_backwards_recurrence_fraction&) = delete;
0054
0055 Recurrence r;
0056 int k;
0057 };
0058
0059 template <class R, class T>
0060 struct recurrence_reverser
0061 {
0062 recurrence_reverser(const R& r) : r(r) {}
0063 std::tuple<T, T, T> operator()(int i)
0064 {
0065 using std::swap;
0066 std::tuple<T, T, T> t = r(-i);
0067 swap(std::get<0>(t), std::get<2>(t));
0068 return t;
0069 }
0070 R r;
0071 };
0072
0073 template <class Recurrence>
0074 struct recurrence_offsetter
0075 {
0076 typedef decltype(std::declval<Recurrence&>()(0)) result_type;
0077 recurrence_offsetter(Recurrence const& rr, int offset) : r(rr), k(offset) {}
0078 result_type operator()(int i)
0079 {
0080 return r(i + k);
0081 }
0082 private:
0083 Recurrence r;
0084 int k;
0085 };
0086
0087
0088
0089 }
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 template <class Recurrence, class T>
0101 T function_ratio_from_backwards_recurrence(const Recurrence& r, const T& factor, std::uintmax_t& max_iter)
0102 {
0103 detail::function_ratio_from_backwards_recurrence_fraction<Recurrence> f(r);
0104 return boost::math::tools::continued_fraction_a(f, factor, max_iter);
0105 }
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 template <class Recurrence, class T>
0122 T function_ratio_from_forwards_recurrence(const Recurrence& r, const T& factor, std::uintmax_t& max_iter)
0123 {
0124 boost::math::tools::detail::function_ratio_from_backwards_recurrence_fraction<boost::math::tools::detail::recurrence_reverser<Recurrence, T> > f(r);
0125 return boost::math::tools::continued_fraction_a(f, factor, max_iter);
0126 }
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 template <class NextCoefs, class T>
0142 inline T apply_recurrence_relation_forward(const NextCoefs& get_coefs, unsigned number_of_steps, T first, T second, long long* log_scaling = nullptr, T* previous = nullptr)
0143 {
0144 BOOST_MATH_STD_USING
0145 using std::tuple;
0146 using std::get;
0147 using std::swap;
0148
0149 T third;
0150 T a, b, c;
0151
0152 for (unsigned k = 0; k < number_of_steps; ++k)
0153 {
0154 tie(a, b, c) = get_coefs(k);
0155
0156 if ((log_scaling) &&
0157 ((fabs(tools::max_value<T>() * (c / (a * 2048))) < fabs(first))
0158 || (fabs(tools::max_value<T>() * (c / (b * 2048))) < fabs(second))
0159 || (fabs(tools::min_value<T>() * (c * 2048 / a)) > fabs(first))
0160 || (fabs(tools::min_value<T>() * (c * 2048 / b)) > fabs(second))
0161 ))
0162
0163 {
0164
0165 long long log_scale = lltrunc(log(fabs(second)));
0166 T scale = exp(T(-log_scale));
0167 second *= scale;
0168 first *= scale;
0169 *log_scaling += log_scale;
0170 }
0171
0172 third = (a / -c) * first + (b / -c) * second;
0173 BOOST_MATH_ASSERT((boost::math::isfinite)(third));
0174
0175
0176 swap(first, second);
0177 swap(second, third);
0178 }
0179
0180 if (previous)
0181 *previous = first;
0182
0183 return second;
0184 }
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 template <class T, class NextCoefs>
0198 inline T apply_recurrence_relation_backward(const NextCoefs& get_coefs, unsigned number_of_steps, T first, T second, long long* log_scaling = nullptr, T* previous = nullptr)
0199 {
0200 BOOST_MATH_STD_USING
0201 using std::tuple;
0202 using std::get;
0203 using std::swap;
0204
0205 T next;
0206 T a, b, c;
0207
0208 for (unsigned k = 0; k < number_of_steps; ++k)
0209 {
0210 tie(a, b, c) = get_coefs(-static_cast<int>(k));
0211
0212 if ((log_scaling) && (second != 0) &&
0213 ( (fabs(tools::max_value<T>() * (a / b) / 2048) < fabs(second))
0214 || (fabs(tools::max_value<T>() * (a / c) / 2048) < fabs(first))
0215 || (fabs(tools::min_value<T>() * (a / b) * 2048) > fabs(second))
0216 || (fabs(tools::min_value<T>() * (a / c) * 2048) > fabs(first))
0217 ))
0218 {
0219
0220 int log_scale = itrunc(log(fabs(second)));
0221 T scale = exp(T(-log_scale));
0222 second *= scale;
0223 first *= scale;
0224 *log_scaling += log_scale;
0225 }
0226
0227 next = (b / -a) * second + (c / -a) * first;
0228 BOOST_MATH_ASSERT((boost::math::isfinite)(next));
0229
0230 swap(first, second);
0231 swap(second, next);
0232 }
0233
0234 if (previous)
0235 *previous = first;
0236
0237 return second;
0238 }
0239
0240 template <class Recurrence>
0241 struct forward_recurrence_iterator
0242 {
0243 typedef typename std::remove_reference<decltype(std::get<0>(std::declval<Recurrence&>()(0)))>::type value_type;
0244
0245 forward_recurrence_iterator(const Recurrence& r, value_type f_n_minus_1, value_type f_n)
0246 : f_n_minus_1(f_n_minus_1), f_n(f_n), coef(r), k(0) {}
0247
0248 forward_recurrence_iterator(const Recurrence& r, value_type f_n)
0249 : f_n(f_n), coef(r), k(0)
0250 {
0251 std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<boost::math::policies::policy<> >();
0252 f_n_minus_1 = f_n * boost::math::tools::function_ratio_from_forwards_recurrence(detail::recurrence_offsetter<Recurrence>(r, -1), value_type(boost::math::tools::epsilon<value_type>() * 2), max_iter);
0253 boost::math::policies::check_series_iterations<value_type>("forward_recurrence_iterator<>::forward_recurrence_iterator", max_iter, boost::math::policies::policy<>());
0254 }
0255
0256 forward_recurrence_iterator& operator++()
0257 {
0258 using std::swap;
0259 value_type a, b, c;
0260 std::tie(a, b, c) = coef(k);
0261 value_type f_n_plus_1 = a * f_n_minus_1 / -c + b * f_n / -c;
0262 swap(f_n_minus_1, f_n);
0263 swap(f_n, f_n_plus_1);
0264 ++k;
0265 return *this;
0266 }
0267
0268 forward_recurrence_iterator operator++(int)
0269 {
0270 forward_recurrence_iterator t(*this);
0271 ++(*this);
0272 return t;
0273 }
0274
0275 value_type operator*() { return f_n; }
0276
0277 value_type f_n_minus_1, f_n;
0278 Recurrence coef;
0279 int k;
0280 };
0281
0282 template <class Recurrence>
0283 struct backward_recurrence_iterator
0284 {
0285 typedef typename std::remove_reference<decltype(std::get<0>(std::declval<Recurrence&>()(0)))>::type value_type;
0286
0287 backward_recurrence_iterator(const Recurrence& r, value_type f_n_plus_1, value_type f_n)
0288 : f_n_plus_1(f_n_plus_1), f_n(f_n), coef(r), k(0) {}
0289
0290 backward_recurrence_iterator(const Recurrence& r, value_type f_n)
0291 : f_n(f_n), coef(r), k(0)
0292 {
0293 std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<boost::math::policies::policy<> >();
0294 f_n_plus_1 = f_n * boost::math::tools::function_ratio_from_backwards_recurrence(detail::recurrence_offsetter<Recurrence>(r, 1), value_type(boost::math::tools::epsilon<value_type>() * 2), max_iter);
0295 boost::math::policies::check_series_iterations<value_type>("backward_recurrence_iterator<>::backward_recurrence_iterator", max_iter, boost::math::policies::policy<>());
0296 }
0297
0298 backward_recurrence_iterator& operator++()
0299 {
0300 using std::swap;
0301 value_type a, b, c;
0302 std::tie(a, b, c) = coef(k);
0303 value_type f_n_minus_1 = c * f_n_plus_1 / -a + b * f_n / -a;
0304 swap(f_n_plus_1, f_n);
0305 swap(f_n, f_n_minus_1);
0306 --k;
0307 return *this;
0308 }
0309
0310 backward_recurrence_iterator operator++(int)
0311 {
0312 backward_recurrence_iterator t(*this);
0313 ++(*this);
0314 return t;
0315 }
0316
0317 value_type operator*() { return f_n; }
0318
0319 value_type f_n_plus_1, f_n;
0320 Recurrence coef;
0321 int k;
0322 };
0323
0324 }
0325 }
0326 }
0327
0328 #endif