Chris@16
|
1 // Copyright (c) 2006 Xiaogang Zhang
|
Chris@16
|
2 // Use, modification and distribution are subject to the
|
Chris@16
|
3 // Boost Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_MATH_BESSEL_IK_HPP
|
Chris@16
|
7 #define BOOST_MATH_BESSEL_IK_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #ifdef _MSC_VER
|
Chris@16
|
10 #pragma once
|
Chris@16
|
11 #endif
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/math/special_functions/round.hpp>
|
Chris@16
|
14 #include <boost/math/special_functions/gamma.hpp>
|
Chris@16
|
15 #include <boost/math/special_functions/sin_pi.hpp>
|
Chris@16
|
16 #include <boost/math/constants/constants.hpp>
|
Chris@16
|
17 #include <boost/math/policies/error_handling.hpp>
|
Chris@16
|
18 #include <boost/math/tools/config.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 // Modified Bessel functions of the first and second kind of fractional order
|
Chris@16
|
21
|
Chris@16
|
22 namespace boost { namespace math {
|
Chris@16
|
23
|
Chris@16
|
24 namespace detail {
|
Chris@16
|
25
|
Chris@16
|
26 template <class T, class Policy>
|
Chris@16
|
27 struct cyl_bessel_i_small_z
|
Chris@16
|
28 {
|
Chris@16
|
29 typedef T result_type;
|
Chris@16
|
30
|
Chris@16
|
31 cyl_bessel_i_small_z(T v_, T z_) : k(0), v(v_), mult(z_*z_/4)
|
Chris@16
|
32 {
|
Chris@16
|
33 BOOST_MATH_STD_USING
|
Chris@16
|
34 term = 1;
|
Chris@16
|
35 }
|
Chris@16
|
36
|
Chris@16
|
37 T operator()()
|
Chris@16
|
38 {
|
Chris@16
|
39 T result = term;
|
Chris@16
|
40 ++k;
|
Chris@16
|
41 term *= mult / k;
|
Chris@16
|
42 term /= k + v;
|
Chris@16
|
43 return result;
|
Chris@16
|
44 }
|
Chris@16
|
45 private:
|
Chris@16
|
46 unsigned k;
|
Chris@16
|
47 T v;
|
Chris@16
|
48 T term;
|
Chris@16
|
49 T mult;
|
Chris@16
|
50 };
|
Chris@16
|
51
|
Chris@16
|
52 template <class T, class Policy>
|
Chris@16
|
53 inline T bessel_i_small_z_series(T v, T x, const Policy& pol)
|
Chris@16
|
54 {
|
Chris@16
|
55 BOOST_MATH_STD_USING
|
Chris@16
|
56 T prefix;
|
Chris@16
|
57 if(v < max_factorial<T>::value)
|
Chris@16
|
58 {
|
Chris@16
|
59 prefix = pow(x / 2, v) / boost::math::tgamma(v + 1, pol);
|
Chris@16
|
60 }
|
Chris@16
|
61 else
|
Chris@16
|
62 {
|
Chris@16
|
63 prefix = v * log(x / 2) - boost::math::lgamma(v + 1, pol);
|
Chris@16
|
64 prefix = exp(prefix);
|
Chris@16
|
65 }
|
Chris@16
|
66 if(prefix == 0)
|
Chris@16
|
67 return prefix;
|
Chris@16
|
68
|
Chris@16
|
69 cyl_bessel_i_small_z<T, Policy> s(v, x);
|
Chris@16
|
70 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
71 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
Chris@16
|
72 T zero = 0;
|
Chris@16
|
73 T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
|
Chris@16
|
74 #else
|
Chris@16
|
75 T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
|
Chris@16
|
76 #endif
|
Chris@16
|
77 policies::check_series_iterations<T>("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
|
Chris@16
|
78 return prefix * result;
|
Chris@16
|
79 }
|
Chris@16
|
80
|
Chris@16
|
81 // Calculate K(v, x) and K(v+1, x) by method analogous to
|
Chris@16
|
82 // Temme, Journal of Computational Physics, vol 21, 343 (1976)
|
Chris@16
|
83 template <typename T, typename Policy>
|
Chris@16
|
84 int temme_ik(T v, T x, T* K, T* K1, const Policy& pol)
|
Chris@16
|
85 {
|
Chris@16
|
86 T f, h, p, q, coef, sum, sum1, tolerance;
|
Chris@16
|
87 T a, b, c, d, sigma, gamma1, gamma2;
|
Chris@16
|
88 unsigned long k;
|
Chris@16
|
89
|
Chris@16
|
90 BOOST_MATH_STD_USING
|
Chris@16
|
91 using namespace boost::math::tools;
|
Chris@16
|
92 using namespace boost::math::constants;
|
Chris@16
|
93
|
Chris@16
|
94
|
Chris@16
|
95 // |x| <= 2, Temme series converge rapidly
|
Chris@16
|
96 // |x| > 2, the larger the |x|, the slower the convergence
|
Chris@16
|
97 BOOST_ASSERT(abs(x) <= 2);
|
Chris@16
|
98 BOOST_ASSERT(abs(v) <= 0.5f);
|
Chris@16
|
99
|
Chris@16
|
100 T gp = boost::math::tgamma1pm1(v, pol);
|
Chris@16
|
101 T gm = boost::math::tgamma1pm1(-v, pol);
|
Chris@16
|
102
|
Chris@16
|
103 a = log(x / 2);
|
Chris@16
|
104 b = exp(v * a);
|
Chris@16
|
105 sigma = -a * v;
|
Chris@16
|
106 c = abs(v) < tools::epsilon<T>() ?
|
Chris@16
|
107 T(1) : T(boost::math::sin_pi(v) / (v * pi<T>()));
|
Chris@16
|
108 d = abs(sigma) < tools::epsilon<T>() ?
|
Chris@16
|
109 T(1) : T(sinh(sigma) / sigma);
|
Chris@16
|
110 gamma1 = abs(v) < tools::epsilon<T>() ?
|
Chris@16
|
111 T(-euler<T>()) : T((0.5f / v) * (gp - gm) * c);
|
Chris@16
|
112 gamma2 = (2 + gp + gm) * c / 2;
|
Chris@16
|
113
|
Chris@16
|
114 // initial values
|
Chris@16
|
115 p = (gp + 1) / (2 * b);
|
Chris@16
|
116 q = (1 + gm) * b / 2;
|
Chris@16
|
117 f = (cosh(sigma) * gamma1 + d * (-a) * gamma2) / c;
|
Chris@16
|
118 h = p;
|
Chris@16
|
119 coef = 1;
|
Chris@16
|
120 sum = coef * f;
|
Chris@16
|
121 sum1 = coef * h;
|
Chris@16
|
122
|
Chris@16
|
123 BOOST_MATH_INSTRUMENT_VARIABLE(p);
|
Chris@16
|
124 BOOST_MATH_INSTRUMENT_VARIABLE(q);
|
Chris@16
|
125 BOOST_MATH_INSTRUMENT_VARIABLE(f);
|
Chris@16
|
126 BOOST_MATH_INSTRUMENT_VARIABLE(sigma);
|
Chris@16
|
127 BOOST_MATH_INSTRUMENT_CODE(sinh(sigma));
|
Chris@16
|
128 BOOST_MATH_INSTRUMENT_VARIABLE(gamma1);
|
Chris@16
|
129 BOOST_MATH_INSTRUMENT_VARIABLE(gamma2);
|
Chris@16
|
130 BOOST_MATH_INSTRUMENT_VARIABLE(c);
|
Chris@16
|
131 BOOST_MATH_INSTRUMENT_VARIABLE(d);
|
Chris@16
|
132 BOOST_MATH_INSTRUMENT_VARIABLE(a);
|
Chris@16
|
133
|
Chris@16
|
134 // series summation
|
Chris@16
|
135 tolerance = tools::epsilon<T>();
|
Chris@16
|
136 for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
|
Chris@16
|
137 {
|
Chris@16
|
138 f = (k * f + p + q) / (k*k - v*v);
|
Chris@16
|
139 p /= k - v;
|
Chris@16
|
140 q /= k + v;
|
Chris@16
|
141 h = p - k * f;
|
Chris@16
|
142 coef *= x * x / (4 * k);
|
Chris@16
|
143 sum += coef * f;
|
Chris@16
|
144 sum1 += coef * h;
|
Chris@16
|
145 if (abs(coef * f) < abs(sum) * tolerance)
|
Chris@16
|
146 {
|
Chris@16
|
147 break;
|
Chris@16
|
148 }
|
Chris@16
|
149 }
|
Chris@16
|
150 policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in temme_ik", k, pol);
|
Chris@16
|
151
|
Chris@16
|
152 *K = sum;
|
Chris@16
|
153 *K1 = 2 * sum1 / x;
|
Chris@16
|
154
|
Chris@16
|
155 return 0;
|
Chris@16
|
156 }
|
Chris@16
|
157
|
Chris@16
|
158 // Evaluate continued fraction fv = I_(v+1) / I_v, derived from
|
Chris@16
|
159 // Abramowitz and Stegun, Handbook of Mathematical Functions, 1972, 9.1.73
|
Chris@16
|
160 template <typename T, typename Policy>
|
Chris@16
|
161 int CF1_ik(T v, T x, T* fv, const Policy& pol)
|
Chris@16
|
162 {
|
Chris@16
|
163 T C, D, f, a, b, delta, tiny, tolerance;
|
Chris@16
|
164 unsigned long k;
|
Chris@16
|
165
|
Chris@16
|
166 BOOST_MATH_STD_USING
|
Chris@16
|
167
|
Chris@16
|
168 // |x| <= |v|, CF1_ik converges rapidly
|
Chris@16
|
169 // |x| > |v|, CF1_ik needs O(|x|) iterations to converge
|
Chris@16
|
170
|
Chris@16
|
171 // modified Lentz's method, see
|
Chris@16
|
172 // Lentz, Applied Optics, vol 15, 668 (1976)
|
Chris@16
|
173 tolerance = 2 * tools::epsilon<T>();
|
Chris@16
|
174 BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
|
Chris@16
|
175 tiny = sqrt(tools::min_value<T>());
|
Chris@16
|
176 BOOST_MATH_INSTRUMENT_VARIABLE(tiny);
|
Chris@16
|
177 C = f = tiny; // b0 = 0, replace with tiny
|
Chris@16
|
178 D = 0;
|
Chris@16
|
179 for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
|
Chris@16
|
180 {
|
Chris@16
|
181 a = 1;
|
Chris@16
|
182 b = 2 * (v + k) / x;
|
Chris@16
|
183 C = b + a / C;
|
Chris@16
|
184 D = b + a * D;
|
Chris@16
|
185 if (C == 0) { C = tiny; }
|
Chris@16
|
186 if (D == 0) { D = tiny; }
|
Chris@16
|
187 D = 1 / D;
|
Chris@16
|
188 delta = C * D;
|
Chris@16
|
189 f *= delta;
|
Chris@16
|
190 BOOST_MATH_INSTRUMENT_VARIABLE(delta-1);
|
Chris@16
|
191 if (abs(delta - 1) <= tolerance)
|
Chris@16
|
192 {
|
Chris@16
|
193 break;
|
Chris@16
|
194 }
|
Chris@16
|
195 }
|
Chris@16
|
196 BOOST_MATH_INSTRUMENT_VARIABLE(k);
|
Chris@16
|
197 policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in CF1_ik", k, pol);
|
Chris@16
|
198
|
Chris@16
|
199 *fv = f;
|
Chris@16
|
200
|
Chris@16
|
201 return 0;
|
Chris@16
|
202 }
|
Chris@16
|
203
|
Chris@16
|
204 // Calculate K(v, x) and K(v+1, x) by evaluating continued fraction
|
Chris@16
|
205 // z1 / z0 = U(v+1.5, 2v+1, 2x) / U(v+0.5, 2v+1, 2x), see
|
Chris@16
|
206 // Thompson and Barnett, Computer Physics Communications, vol 47, 245 (1987)
|
Chris@16
|
207 template <typename T, typename Policy>
|
Chris@16
|
208 int CF2_ik(T v, T x, T* Kv, T* Kv1, const Policy& pol)
|
Chris@16
|
209 {
|
Chris@16
|
210 BOOST_MATH_STD_USING
|
Chris@16
|
211 using namespace boost::math::constants;
|
Chris@16
|
212
|
Chris@16
|
213 T S, C, Q, D, f, a, b, q, delta, tolerance, current, prev;
|
Chris@16
|
214 unsigned long k;
|
Chris@16
|
215
|
Chris@16
|
216 // |x| >= |v|, CF2_ik converges rapidly
|
Chris@16
|
217 // |x| -> 0, CF2_ik fails to converge
|
Chris@16
|
218
|
Chris@16
|
219 BOOST_ASSERT(abs(x) > 1);
|
Chris@16
|
220
|
Chris@16
|
221 // Steed's algorithm, see Thompson and Barnett,
|
Chris@16
|
222 // Journal of Computational Physics, vol 64, 490 (1986)
|
Chris@16
|
223 tolerance = tools::epsilon<T>();
|
Chris@16
|
224 a = v * v - 0.25f;
|
Chris@16
|
225 b = 2 * (x + 1); // b1
|
Chris@16
|
226 D = 1 / b; // D1 = 1 / b1
|
Chris@16
|
227 f = delta = D; // f1 = delta1 = D1, coincidence
|
Chris@16
|
228 prev = 0; // q0
|
Chris@16
|
229 current = 1; // q1
|
Chris@16
|
230 Q = C = -a; // Q1 = C1 because q1 = 1
|
Chris@16
|
231 S = 1 + Q * delta; // S1
|
Chris@16
|
232 BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
|
Chris@16
|
233 BOOST_MATH_INSTRUMENT_VARIABLE(a);
|
Chris@16
|
234 BOOST_MATH_INSTRUMENT_VARIABLE(b);
|
Chris@16
|
235 BOOST_MATH_INSTRUMENT_VARIABLE(D);
|
Chris@16
|
236 BOOST_MATH_INSTRUMENT_VARIABLE(f);
|
Chris@16
|
237
|
Chris@16
|
238 for (k = 2; k < policies::get_max_series_iterations<Policy>(); k++) // starting from 2
|
Chris@16
|
239 {
|
Chris@16
|
240 // continued fraction f = z1 / z0
|
Chris@16
|
241 a -= 2 * (k - 1);
|
Chris@16
|
242 b += 2;
|
Chris@16
|
243 D = 1 / (b + a * D);
|
Chris@16
|
244 delta *= b * D - 1;
|
Chris@16
|
245 f += delta;
|
Chris@16
|
246
|
Chris@16
|
247 // series summation S = 1 + \sum_{n=1}^{\infty} C_n * z_n / z_0
|
Chris@16
|
248 q = (prev - (b - 2) * current) / a;
|
Chris@16
|
249 prev = current;
|
Chris@16
|
250 current = q; // forward recurrence for q
|
Chris@16
|
251 C *= -a / k;
|
Chris@16
|
252 Q += C * q;
|
Chris@16
|
253 S += Q * delta;
|
Chris@16
|
254 //
|
Chris@16
|
255 // Under some circumstances q can grow very small and C very
|
Chris@16
|
256 // large, leading to under/overflow. This is particularly an
|
Chris@16
|
257 // issue for types which have many digits precision but a narrow
|
Chris@16
|
258 // exponent range. A typical example being a "double double" type.
|
Chris@16
|
259 // To avoid this situation we can normalise q (and related prev/current)
|
Chris@16
|
260 // and C. All other variables remain unchanged in value. A typical
|
Chris@16
|
261 // test case occurs when x is close to 2, for example cyl_bessel_k(9.125, 2.125).
|
Chris@16
|
262 //
|
Chris@16
|
263 if(q < tools::epsilon<T>())
|
Chris@16
|
264 {
|
Chris@16
|
265 C *= q;
|
Chris@16
|
266 prev /= q;
|
Chris@16
|
267 current /= q;
|
Chris@16
|
268 q = 1;
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 // S converges slower than f
|
Chris@16
|
272 BOOST_MATH_INSTRUMENT_VARIABLE(Q * delta);
|
Chris@16
|
273 BOOST_MATH_INSTRUMENT_VARIABLE(abs(S) * tolerance);
|
Chris@101
|
274 BOOST_MATH_INSTRUMENT_VARIABLE(S);
|
Chris@16
|
275 if (abs(Q * delta) < abs(S) * tolerance)
|
Chris@16
|
276 {
|
Chris@16
|
277 break;
|
Chris@16
|
278 }
|
Chris@16
|
279 }
|
Chris@16
|
280 policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in CF2_ik", k, pol);
|
Chris@16
|
281
|
Chris@101
|
282 if(x >= tools::log_max_value<T>())
|
Chris@101
|
283 *Kv = exp(0.5f * log(pi<T>() / (2 * x)) - x - log(S));
|
Chris@101
|
284 else
|
Chris@101
|
285 *Kv = sqrt(pi<T>() / (2 * x)) * exp(-x) / S;
|
Chris@16
|
286 *Kv1 = *Kv * (0.5f + v + x + (v * v - 0.25f) * f) / x;
|
Chris@16
|
287 BOOST_MATH_INSTRUMENT_VARIABLE(*Kv);
|
Chris@16
|
288 BOOST_MATH_INSTRUMENT_VARIABLE(*Kv1);
|
Chris@16
|
289
|
Chris@16
|
290 return 0;
|
Chris@16
|
291 }
|
Chris@16
|
292
|
Chris@16
|
293 enum{
|
Chris@16
|
294 need_i = 1,
|
Chris@16
|
295 need_k = 2
|
Chris@16
|
296 };
|
Chris@16
|
297
|
Chris@16
|
298 // Compute I(v, x) and K(v, x) simultaneously by Temme's method, see
|
Chris@16
|
299 // Temme, Journal of Computational Physics, vol 19, 324 (1975)
|
Chris@16
|
300 template <typename T, typename Policy>
|
Chris@16
|
301 int bessel_ik(T v, T x, T* I, T* K, int kind, const Policy& pol)
|
Chris@16
|
302 {
|
Chris@16
|
303 // Kv1 = K_(v+1), fv = I_(v+1) / I_v
|
Chris@16
|
304 // Ku1 = K_(u+1), fu = I_(u+1) / I_u
|
Chris@16
|
305 T u, Iv, Kv, Kv1, Ku, Ku1, fv;
|
Chris@16
|
306 T W, current, prev, next;
|
Chris@16
|
307 bool reflect = false;
|
Chris@16
|
308 unsigned n, k;
|
Chris@16
|
309 int org_kind = kind;
|
Chris@16
|
310 BOOST_MATH_INSTRUMENT_VARIABLE(v);
|
Chris@16
|
311 BOOST_MATH_INSTRUMENT_VARIABLE(x);
|
Chris@16
|
312 BOOST_MATH_INSTRUMENT_VARIABLE(kind);
|
Chris@16
|
313
|
Chris@16
|
314 BOOST_MATH_STD_USING
|
Chris@16
|
315 using namespace boost::math::tools;
|
Chris@16
|
316 using namespace boost::math::constants;
|
Chris@16
|
317
|
Chris@16
|
318 static const char* function = "boost::math::bessel_ik<%1%>(%1%,%1%)";
|
Chris@16
|
319
|
Chris@16
|
320 if (v < 0)
|
Chris@16
|
321 {
|
Chris@16
|
322 reflect = true;
|
Chris@16
|
323 v = -v; // v is non-negative from here
|
Chris@16
|
324 kind |= need_k;
|
Chris@16
|
325 }
|
Chris@16
|
326 n = iround(v, pol);
|
Chris@16
|
327 u = v - n; // -1/2 <= u < 1/2
|
Chris@16
|
328 BOOST_MATH_INSTRUMENT_VARIABLE(n);
|
Chris@16
|
329 BOOST_MATH_INSTRUMENT_VARIABLE(u);
|
Chris@16
|
330
|
Chris@16
|
331 if (x < 0)
|
Chris@16
|
332 {
|
Chris@16
|
333 *I = *K = policies::raise_domain_error<T>(function,
|
Chris@16
|
334 "Got x = %1% but real argument x must be non-negative, complex number result not supported.", x, pol);
|
Chris@16
|
335 return 1;
|
Chris@16
|
336 }
|
Chris@16
|
337 if (x == 0)
|
Chris@16
|
338 {
|
Chris@16
|
339 Iv = (v == 0) ? static_cast<T>(1) : static_cast<T>(0);
|
Chris@16
|
340 if(kind & need_k)
|
Chris@16
|
341 {
|
Chris@16
|
342 Kv = policies::raise_overflow_error<T>(function, 0, pol);
|
Chris@16
|
343 }
|
Chris@16
|
344 else
|
Chris@16
|
345 {
|
Chris@16
|
346 Kv = std::numeric_limits<T>::quiet_NaN(); // any value will do
|
Chris@16
|
347 }
|
Chris@16
|
348
|
Chris@16
|
349 if(reflect && (kind & need_i))
|
Chris@16
|
350 {
|
Chris@16
|
351 T z = (u + n % 2);
|
Chris@16
|
352 Iv = boost::math::sin_pi(z, pol) == 0 ?
|
Chris@16
|
353 Iv :
|
Chris@16
|
354 policies::raise_overflow_error<T>(function, 0, pol); // reflection formula
|
Chris@16
|
355 }
|
Chris@16
|
356
|
Chris@16
|
357 *I = Iv;
|
Chris@16
|
358 *K = Kv;
|
Chris@16
|
359 return 0;
|
Chris@16
|
360 }
|
Chris@16
|
361
|
Chris@16
|
362 // x is positive until reflection
|
Chris@16
|
363 W = 1 / x; // Wronskian
|
Chris@16
|
364 if (x <= 2) // x in (0, 2]
|
Chris@16
|
365 {
|
Chris@16
|
366 temme_ik(u, x, &Ku, &Ku1, pol); // Temme series
|
Chris@16
|
367 }
|
Chris@16
|
368 else // x in (2, \infty)
|
Chris@16
|
369 {
|
Chris@16
|
370 CF2_ik(u, x, &Ku, &Ku1, pol); // continued fraction CF2_ik
|
Chris@16
|
371 }
|
Chris@16
|
372 BOOST_MATH_INSTRUMENT_VARIABLE(Ku);
|
Chris@16
|
373 BOOST_MATH_INSTRUMENT_VARIABLE(Ku1);
|
Chris@16
|
374 prev = Ku;
|
Chris@16
|
375 current = Ku1;
|
Chris@16
|
376 T scale = 1;
|
Chris@16
|
377 for (k = 1; k <= n; k++) // forward recurrence for K
|
Chris@16
|
378 {
|
Chris@16
|
379 T fact = 2 * (u + k) / x;
|
Chris@16
|
380 if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
|
Chris@16
|
381 {
|
Chris@16
|
382 prev /= current;
|
Chris@16
|
383 scale /= current;
|
Chris@16
|
384 current = 1;
|
Chris@16
|
385 }
|
Chris@16
|
386 next = fact * current + prev;
|
Chris@16
|
387 prev = current;
|
Chris@16
|
388 current = next;
|
Chris@16
|
389 }
|
Chris@16
|
390 Kv = prev;
|
Chris@16
|
391 Kv1 = current;
|
Chris@16
|
392 BOOST_MATH_INSTRUMENT_VARIABLE(Kv);
|
Chris@16
|
393 BOOST_MATH_INSTRUMENT_VARIABLE(Kv1);
|
Chris@16
|
394 if(kind & need_i)
|
Chris@16
|
395 {
|
Chris@16
|
396 T lim = (4 * v * v + 10) / (8 * x);
|
Chris@16
|
397 lim *= lim;
|
Chris@16
|
398 lim *= lim;
|
Chris@16
|
399 lim /= 24;
|
Chris@16
|
400 if((lim < tools::epsilon<T>() * 10) && (x > 100))
|
Chris@16
|
401 {
|
Chris@16
|
402 // x is huge compared to v, CF1 may be very slow
|
Chris@16
|
403 // to converge so use asymptotic expansion for large
|
Chris@16
|
404 // x case instead. Note that the asymptotic expansion
|
Chris@16
|
405 // isn't very accurate - so it's deliberately very hard
|
Chris@16
|
406 // to get here - probably we're going to overflow:
|
Chris@16
|
407 Iv = asymptotic_bessel_i_large_x(v, x, pol);
|
Chris@16
|
408 }
|
Chris@16
|
409 else if((v > 0) && (x / v < 0.25))
|
Chris@16
|
410 {
|
Chris@16
|
411 Iv = bessel_i_small_z_series(v, x, pol);
|
Chris@16
|
412 }
|
Chris@16
|
413 else
|
Chris@16
|
414 {
|
Chris@16
|
415 CF1_ik(v, x, &fv, pol); // continued fraction CF1_ik
|
Chris@16
|
416 Iv = scale * W / (Kv * fv + Kv1); // Wronskian relation
|
Chris@16
|
417 }
|
Chris@16
|
418 }
|
Chris@16
|
419 else
|
Chris@16
|
420 Iv = std::numeric_limits<T>::quiet_NaN(); // any value will do
|
Chris@16
|
421
|
Chris@16
|
422 if (reflect)
|
Chris@16
|
423 {
|
Chris@16
|
424 T z = (u + n % 2);
|
Chris@16
|
425 T fact = (2 / pi<T>()) * (boost::math::sin_pi(z) * Kv);
|
Chris@16
|
426 if(fact == 0)
|
Chris@16
|
427 *I = Iv;
|
Chris@16
|
428 else if(tools::max_value<T>() * scale < fact)
|
Chris@16
|
429 *I = (org_kind & need_i) ? T(sign(fact) * sign(scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
|
Chris@16
|
430 else
|
Chris@16
|
431 *I = Iv + fact / scale; // reflection formula
|
Chris@16
|
432 }
|
Chris@16
|
433 else
|
Chris@16
|
434 {
|
Chris@16
|
435 *I = Iv;
|
Chris@16
|
436 }
|
Chris@16
|
437 if(tools::max_value<T>() * scale < Kv)
|
Chris@16
|
438 *K = (org_kind & need_k) ? T(sign(Kv) * sign(scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
|
Chris@16
|
439 else
|
Chris@16
|
440 *K = Kv / scale;
|
Chris@16
|
441 BOOST_MATH_INSTRUMENT_VARIABLE(*I);
|
Chris@16
|
442 BOOST_MATH_INSTRUMENT_VARIABLE(*K);
|
Chris@16
|
443 return 0;
|
Chris@16
|
444 }
|
Chris@16
|
445
|
Chris@16
|
446 }}} // namespaces
|
Chris@16
|
447
|
Chris@16
|
448 #endif // BOOST_MATH_BESSEL_IK_HPP
|
Chris@16
|
449
|