File indexing completed on 2025-07-05 08:37:14
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* result_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 *result_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* result_I, T* result_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
0326 T scale = 1;
0327 T scale_sign = 1;
0328
0329 if (((kind & need_i) == 0) && (fabs(4 * v * v - 25) / (8 * x) < tools::forth_root_epsilon<T>()))
0330 {
0331
0332 Iv = std::numeric_limits<T>::quiet_NaN();
0333 T mu = 4 * v * v;
0334 T eight_z = 8 * x;
0335 Kv = 1 + (mu - 1) / eight_z + (mu - 1) * (mu - 9) / (2 * eight_z * eight_z) + (mu - 1) * (mu - 9) * (mu - 25) / (6 * eight_z * eight_z * eight_z);
0336 Kv *= exp(-x) * constants::root_pi<T>() / sqrt(2 * x);
0337 }
0338 else
0339 {
0340 n = iround(v, pol);
0341 u = v - n;
0342 BOOST_MATH_INSTRUMENT_VARIABLE(n);
0343 BOOST_MATH_INSTRUMENT_VARIABLE(u);
0344
0345 BOOST_MATH_ASSERT(x > 0);
0346
0347
0348 W = 1 / x;
0349 if (x <= 2)
0350 {
0351 temme_ik(u, x, &Ku, &Ku1, pol);
0352 }
0353 else
0354 {
0355 CF2_ik(u, x, &Ku, &Ku1, pol);
0356 }
0357 BOOST_MATH_INSTRUMENT_VARIABLE(Ku);
0358 BOOST_MATH_INSTRUMENT_VARIABLE(Ku1);
0359 prev = Ku;
0360 current = Ku1;
0361 for (k = 1; k <= n; k++)
0362 {
0363 T fact = 2 * (u + k) / x;
0364
0365
0366
0367
0368
0369 const bool will_overflow = (fact < 1)
0370 ? tools::max_value<T>() * (1 - fact) > fabs(prev)
0371 : false;
0372 if (!will_overflow && ((tools::max_value<T>() - fabs(prev)) / fact < fabs(current)))
0373 {
0374 prev /= current;
0375 scale /= current;
0376 scale_sign *= ((boost::math::signbit)(current) ? -1 : 1);
0377 current = 1;
0378 }
0379 next = fact * current + prev;
0380 prev = current;
0381 current = next;
0382 }
0383 Kv = prev;
0384 Kv1 = current;
0385 BOOST_MATH_INSTRUMENT_VARIABLE(Kv);
0386 BOOST_MATH_INSTRUMENT_VARIABLE(Kv1);
0387 if (kind & need_i)
0388 {
0389 T lim = (4 * v * v + 10) / (8 * x);
0390 lim *= lim;
0391 lim *= lim;
0392 lim /= 24;
0393 if ((lim < tools::epsilon<T>() * 10) && (x > 100))
0394 {
0395
0396
0397
0398
0399
0400 Iv = asymptotic_bessel_i_large_x(v, x, pol);
0401 }
0402 else if ((v > 0) && (x / v < 0.25))
0403 {
0404 Iv = bessel_i_small_z_series(v, x, pol);
0405 }
0406 else
0407 {
0408 CF1_ik(v, x, &fv, pol);
0409 Iv = scale * W / (Kv * fv + Kv1);
0410 }
0411 }
0412 else
0413 Iv = std::numeric_limits<T>::quiet_NaN();
0414 }
0415 if (reflect)
0416 {
0417 T z = (u + n % 2);
0418 T fact = (2 / pi<T>()) * (boost::math::sin_pi(z, pol) * Kv);
0419 if(fact == 0)
0420 *result_I = Iv;
0421 else if(tools::max_value<T>() * scale < fact)
0422 *result_I = (org_kind & need_i) ? T(sign(fact) * scale_sign * policies::raise_overflow_error<T>(function, nullptr, pol)) : T(0);
0423 else
0424 *result_I = Iv + fact / scale;
0425 }
0426 else
0427 {
0428 *result_I = Iv;
0429 }
0430 if(tools::max_value<T>() * scale < Kv)
0431 *result_K = (org_kind & need_k) ? T(sign(Kv) * scale_sign * policies::raise_overflow_error<T>(function, nullptr, pol)) : T(0);
0432 else
0433 *result_K = Kv / scale;
0434 BOOST_MATH_INSTRUMENT_VARIABLE(*result_I);
0435 BOOST_MATH_INSTRUMENT_VARIABLE(*result_K);
0436 return 0;
0437 }
0438
0439 }}}
0440
0441 #endif
0442