File indexing completed on 2025-01-18 09:39:59
0001
0002
0003
0004
0005
0006 #ifndef BOOST_MATH_BESSEL_IK_HPP
0007 #define BOOST_MATH_BESSEL_IK_HPP
0008
0009 #ifdef _MSC_VER
0010 #pragma once
0011 #endif
0012
0013 #include <cmath>
0014 #include <cstdint>
0015 #include <boost/math/special_functions/round.hpp>
0016 #include <boost/math/special_functions/gamma.hpp>
0017 #include <boost/math/special_functions/sin_pi.hpp>
0018 #include <boost/math/constants/constants.hpp>
0019 #include <boost/math/policies/error_handling.hpp>
0020 #include <boost/math/tools/config.hpp>
0021
0022
0023
0024 namespace boost { namespace math {
0025
0026 namespace detail {
0027
0028 template <class T, class Policy>
0029 struct cyl_bessel_i_small_z
0030 {
0031 typedef T result_type;
0032
0033 cyl_bessel_i_small_z(T v_, T z_) : k(0), v(v_), mult(z_*z_/4)
0034 {
0035 BOOST_MATH_STD_USING
0036 term = 1;
0037 }
0038
0039 T operator()()
0040 {
0041 T result = term;
0042 ++k;
0043 term *= mult / k;
0044 term /= k + v;
0045 return result;
0046 }
0047 private:
0048 unsigned k;
0049 T v;
0050 T term;
0051 T mult;
0052 };
0053
0054 template <class T, class Policy>
0055 inline T bessel_i_small_z_series(T v, T x, const Policy& pol)
0056 {
0057 BOOST_MATH_STD_USING
0058 T prefix;
0059 if(v < max_factorial<T>::value)
0060 {
0061 prefix = pow(x / 2, v) / boost::math::tgamma(v + 1, pol);
0062 }
0063 else
0064 {
0065 prefix = v * log(x / 2) - boost::math::lgamma(v + 1, pol);
0066 prefix = exp(prefix);
0067 }
0068 if(prefix == 0)
0069 return prefix;
0070
0071 cyl_bessel_i_small_z<T, Policy> s(v, x);
0072 std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0073
0074 T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
0075
0076 policies::check_series_iterations<T>("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
0077 return prefix * result;
0078 }
0079
0080
0081
0082 template <typename T, typename Policy>
0083 int temme_ik(T v, T x, T* K, T* K1, const Policy& pol)
0084 {
0085 T f, h, p, q, coef, sum, sum1, tolerance;
0086 T a, b, c, d, sigma, gamma1, gamma2;
0087 unsigned long k;
0088
0089 BOOST_MATH_STD_USING
0090 using namespace boost::math::tools;
0091 using namespace boost::math::constants;
0092
0093
0094
0095
0096 BOOST_MATH_ASSERT(abs(x) <= 2);
0097 BOOST_MATH_ASSERT(abs(v) <= 0.5f);
0098
0099 T gp = boost::math::tgamma1pm1(v, pol);
0100 T gm = boost::math::tgamma1pm1(-v, pol);
0101
0102 a = log(x / 2);
0103 b = exp(v * a);
0104 sigma = -a * v;
0105 c = abs(v) < tools::epsilon<T>() ?
0106 T(1) : T(boost::math::sin_pi(v, pol) / (v * pi<T>()));
0107 d = abs(sigma) < tools::epsilon<T>() ?
0108 T(1) : T(sinh(sigma) / sigma);
0109 gamma1 = abs(v) < tools::epsilon<T>() ?
0110 T(-euler<T>()) : T((0.5f / v) * (gp - gm) * c);
0111 gamma2 = (2 + gp + gm) * c / 2;
0112
0113
0114 p = (gp + 1) / (2 * b);
0115 q = (1 + gm) * b / 2;
0116 f = (cosh(sigma) * gamma1 + d * (-a) * gamma2) / c;
0117 h = p;
0118 coef = 1;
0119 sum = coef * f;
0120 sum1 = coef * h;
0121
0122 BOOST_MATH_INSTRUMENT_VARIABLE(p);
0123 BOOST_MATH_INSTRUMENT_VARIABLE(q);
0124 BOOST_MATH_INSTRUMENT_VARIABLE(f);
0125 BOOST_MATH_INSTRUMENT_VARIABLE(sigma);
0126 BOOST_MATH_INSTRUMENT_CODE(sinh(sigma));
0127 BOOST_MATH_INSTRUMENT_VARIABLE(gamma1);
0128 BOOST_MATH_INSTRUMENT_VARIABLE(gamma2);
0129 BOOST_MATH_INSTRUMENT_VARIABLE(c);
0130 BOOST_MATH_INSTRUMENT_VARIABLE(d);
0131 BOOST_MATH_INSTRUMENT_VARIABLE(a);
0132
0133
0134 tolerance = tools::epsilon<T>();
0135 for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
0136 {
0137 f = (k * f + p + q) / (k*k - v*v);
0138 p /= k - v;
0139 q /= k + v;
0140 h = p - k * f;
0141 coef *= x * x / (4 * k);
0142 sum += coef * f;
0143 sum1 += coef * h;
0144 if (abs(coef * f) < abs(sum) * tolerance)
0145 {
0146 break;
0147 }
0148 }
0149 policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in temme_ik", k, pol);
0150
0151 *K = sum;
0152 *K1 = 2 * sum1 / x;
0153
0154 return 0;
0155 }
0156
0157
0158
0159 template <typename T, typename Policy>
0160 int CF1_ik(T v, T x, T* fv, const Policy& pol)
0161 {
0162 T C, D, f, a, b, delta, tiny, tolerance;
0163 unsigned long k;
0164
0165 BOOST_MATH_STD_USING
0166
0167
0168
0169
0170
0171
0172 tolerance = 2 * tools::epsilon<T>();
0173 BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
0174 tiny = sqrt(tools::min_value<T>());
0175 BOOST_MATH_INSTRUMENT_VARIABLE(tiny);
0176 C = f = tiny;
0177 D = 0;
0178 for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
0179 {
0180 a = 1;
0181 b = 2 * (v + k) / x;
0182 C = b + a / C;
0183 D = b + a * D;
0184 if (C == 0) { C = tiny; }
0185 if (D == 0) { D = tiny; }
0186 D = 1 / D;
0187 delta = C * D;
0188 f *= delta;
0189 BOOST_MATH_INSTRUMENT_VARIABLE(delta-1);
0190 if (abs(delta - 1) <= tolerance)
0191 {
0192 break;
0193 }
0194 }
0195 BOOST_MATH_INSTRUMENT_VARIABLE(k);
0196 policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in CF1_ik", k, pol);
0197
0198 *fv = f;
0199
0200 return 0;
0201 }
0202
0203
0204
0205
0206 template <typename T, typename Policy>
0207 int CF2_ik(T v, T x, T* Kv, T* Kv1, const Policy& pol)
0208 {
0209 BOOST_MATH_STD_USING
0210 using namespace boost::math::constants;
0211
0212 T S, C, Q, D, f, a, b, q, delta, tolerance, current, prev;
0213 unsigned long k;
0214
0215
0216
0217
0218 BOOST_MATH_ASSERT(abs(x) > 1);
0219
0220
0221
0222 tolerance = tools::epsilon<T>();
0223 a = v * v - 0.25f;
0224 b = 2 * (x + 1);
0225 D = 1 / b;
0226 f = delta = D;
0227 prev = 0;
0228 current = 1;
0229 Q = C = -a;
0230 S = 1 + Q * delta;
0231 BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
0232 BOOST_MATH_INSTRUMENT_VARIABLE(a);
0233 BOOST_MATH_INSTRUMENT_VARIABLE(b);
0234 BOOST_MATH_INSTRUMENT_VARIABLE(D);
0235 BOOST_MATH_INSTRUMENT_VARIABLE(f);
0236
0237 for (k = 2; k < policies::get_max_series_iterations<Policy>(); k++)
0238 {
0239
0240 a -= 2 * (k - 1);
0241 b += 2;
0242 D = 1 / (b + a * D);
0243 delta *= b * D - 1;
0244 f += delta;
0245
0246
0247 q = (prev - (b - 2) * current) / a;
0248 prev = current;
0249 current = q;
0250 C *= -a / k;
0251 Q += C * q;
0252 S += Q * delta;
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262 if(q < tools::epsilon<T>())
0263 {
0264 C *= q;
0265 prev /= q;
0266 current /= q;
0267 q = 1;
0268 }
0269
0270
0271 BOOST_MATH_INSTRUMENT_VARIABLE(Q * delta);
0272 BOOST_MATH_INSTRUMENT_VARIABLE(abs(S) * tolerance);
0273 BOOST_MATH_INSTRUMENT_VARIABLE(S);
0274 if (abs(Q * delta) < abs(S) * tolerance)
0275 {
0276 break;
0277 }
0278 }
0279 policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in CF2_ik", k, pol);
0280
0281 if(x >= tools::log_max_value<T>())
0282 *Kv = exp(0.5f * log(pi<T>() / (2 * x)) - x - log(S));
0283 else
0284 *Kv = sqrt(pi<T>() / (2 * x)) * exp(-x) / S;
0285 *Kv1 = *Kv * (0.5f + v + x + (v * v - 0.25f) * f) / x;
0286 BOOST_MATH_INSTRUMENT_VARIABLE(*Kv);
0287 BOOST_MATH_INSTRUMENT_VARIABLE(*Kv1);
0288
0289 return 0;
0290 }
0291
0292 enum{
0293 need_i = 1,
0294 need_k = 2
0295 };
0296
0297
0298
0299 template <typename T, typename Policy>
0300 int bessel_ik(T v, T x, T* I, T* K, int kind, const Policy& pol)
0301 {
0302
0303
0304 T u, Iv, Kv, Kv1, Ku, Ku1, fv;
0305 T W, current, prev, next;
0306 bool reflect = false;
0307 unsigned n, k;
0308 int org_kind = kind;
0309 BOOST_MATH_INSTRUMENT_VARIABLE(v);
0310 BOOST_MATH_INSTRUMENT_VARIABLE(x);
0311 BOOST_MATH_INSTRUMENT_VARIABLE(kind);
0312
0313 BOOST_MATH_STD_USING
0314 using namespace boost::math::tools;
0315 using namespace boost::math::constants;
0316
0317 static const char* function = "boost::math::bessel_ik<%1%>(%1%,%1%)";
0318
0319 if (v < 0)
0320 {
0321 reflect = true;
0322 v = -v;
0323 kind |= need_k;
0324 }
0325 n = iround(v, pol);
0326 u = v - n;
0327 BOOST_MATH_INSTRUMENT_VARIABLE(n);
0328 BOOST_MATH_INSTRUMENT_VARIABLE(u);
0329
0330 if (x < 0)
0331 {
0332 *I = *K = policies::raise_domain_error<T>(function,
0333 "Got x = %1% but real argument x must be non-negative, complex number result not supported.", x, pol);
0334 return 1;
0335 }
0336 if (x == 0)
0337 {
0338 Iv = (v == 0) ? static_cast<T>(1) : static_cast<T>(0);
0339 if(kind & need_k)
0340 {
0341 Kv = policies::raise_overflow_error<T>(function, nullptr, pol);
0342 }
0343 else
0344 {
0345 Kv = std::numeric_limits<T>::quiet_NaN();
0346 }
0347
0348 if(reflect && (kind & need_i))
0349 {
0350 T z = (u + n % 2);
0351 Iv = boost::math::sin_pi(z, pol) == 0 ?
0352 Iv :
0353 policies::raise_overflow_error<T>(function, nullptr, pol);
0354 }
0355
0356 *I = Iv;
0357 *K = Kv;
0358 return 0;
0359 }
0360
0361
0362 W = 1 / x;
0363 if (x <= 2)
0364 {
0365 temme_ik(u, x, &Ku, &Ku1, pol);
0366 }
0367 else
0368 {
0369 CF2_ik(u, x, &Ku, &Ku1, pol);
0370 }
0371 BOOST_MATH_INSTRUMENT_VARIABLE(Ku);
0372 BOOST_MATH_INSTRUMENT_VARIABLE(Ku1);
0373 prev = Ku;
0374 current = Ku1;
0375 T scale = 1;
0376 T scale_sign = 1;
0377 for (k = 1; k <= n; k++)
0378 {
0379 T fact = 2 * (u + k) / x;
0380
0381
0382
0383
0384
0385 const bool will_overflow = (fact < 1)
0386 ? tools::max_value<T>() * (1 - fact) > fabs(prev)
0387 : false;
0388 if(!will_overflow && ((tools::max_value<T>() - fabs(prev)) / fact < fabs(current)))
0389 {
0390 prev /= current;
0391 scale /= current;
0392 scale_sign *= boost::math::sign(current);
0393 current = 1;
0394 }
0395 next = fact * current + prev;
0396 prev = current;
0397 current = next;
0398 }
0399 Kv = prev;
0400 Kv1 = current;
0401 BOOST_MATH_INSTRUMENT_VARIABLE(Kv);
0402 BOOST_MATH_INSTRUMENT_VARIABLE(Kv1);
0403 if(kind & need_i)
0404 {
0405 T lim = (4 * v * v + 10) / (8 * x);
0406 lim *= lim;
0407 lim *= lim;
0408 lim /= 24;
0409 if((lim < tools::epsilon<T>() * 10) && (x > 100))
0410 {
0411
0412
0413
0414
0415
0416 Iv = asymptotic_bessel_i_large_x(v, x, pol);
0417 }
0418 else if((v > 0) && (x / v < 0.25))
0419 {
0420 Iv = bessel_i_small_z_series(v, x, pol);
0421 }
0422 else
0423 {
0424 CF1_ik(v, x, &fv, pol);
0425 Iv = scale * W / (Kv * fv + Kv1);
0426 }
0427 }
0428 else
0429 Iv = std::numeric_limits<T>::quiet_NaN();
0430
0431 if (reflect)
0432 {
0433 T z = (u + n % 2);
0434 T fact = (2 / pi<T>()) * (boost::math::sin_pi(z, pol) * Kv);
0435 if(fact == 0)
0436 *I = Iv;
0437 else if(tools::max_value<T>() * scale < fact)
0438 *I = (org_kind & need_i) ? T(sign(fact) * scale_sign * policies::raise_overflow_error<T>(function, nullptr, pol)) : T(0);
0439 else
0440 *I = Iv + fact / scale;
0441 }
0442 else
0443 {
0444 *I = Iv;
0445 }
0446 if(tools::max_value<T>() * scale < Kv)
0447 *K = (org_kind & need_k) ? T(sign(Kv) * scale_sign * policies::raise_overflow_error<T>(function, nullptr, pol)) : T(0);
0448 else
0449 *K = Kv / scale;
0450 BOOST_MATH_INSTRUMENT_VARIABLE(*I);
0451 BOOST_MATH_INSTRUMENT_VARIABLE(*K);
0452 return 0;
0453 }
0454
0455 }}}
0456
0457 #endif
0458