1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.numerics.special;
39
40 import static org.apache.commons.math3.util.FastMath.abs;
41 import static org.apache.commons.math3.util.FastMath.exp;
42 import static org.apache.commons.math3.util.FastMath.log;
43 import static org.apache.commons.math3.util.FastMath.sqrt;
44
45
46
47
48
49
50
51 public class ModifiedBessel {
52
53 private ModifiedBessel() {
54
55 }
56
57
58
59
60
61
62 private static final double[] A_i0 = {
63 -4.41534164647933937950E-18,
64 3.33079451882223809783E-17,
65 -2.43127984654795469359E-16,
66 1.71539128555513303061E-15,
67 -1.16853328779934516808E-14,
68 7.67618549860493561688E-14,
69 -4.85644678311192946090E-13,
70 2.95505266312963983461E-12,
71 -1.72682629144155570723E-11,
72 9.67580903537323691224E-11,
73 -5.18979560163526290666E-10,
74 2.65982372468238665035E-9,
75 -1.30002500998624804212E-8,
76 6.04699502254191894932E-8,
77 -2.67079385394061173391E-7,
78 1.11738753912010371815E-6,
79 -4.41673835845875056359E-6,
80 1.64484480707288970893E-5,
81 -5.75419501008210370398E-5,
82 1.88502885095841655729E-4,
83 -5.76375574538582365885E-4,
84 1.63947561694133579842E-3,
85 -4.32430999505057594430E-3,
86 1.05464603945949983183E-2,
87 -2.37374148058994688156E-2,
88 4.93052842396707084878E-2,
89 -9.49010970480476444210E-2,
90 1.71620901522208775349E-1,
91 -3.04682672343198398683E-1,
92 6.76795274409476084995E-1
93 };
94
95
96
97
98
99 private static final double[] B_i0 = {
100 -7.23318048787475395456E-18,
101 -4.83050448594418207126E-18,
102 4.46562142029675999901E-17,
103 3.46122286769746109310E-17,
104 -2.82762398051658348494E-16,
105 -3.42548561967721913462E-16,
106 1.77256013305652638360E-15,
107 3.81168066935262242075E-15,
108 -9.55484669882830764870E-15,
109 -4.15056934728722208663E-14,
110 1.54008621752140982691E-14,
111 3.85277838274214270114E-13,
112 7.18012445138366623367E-13,
113 -1.79417853150680611778E-12,
114 -1.32158118404477131188E-11,
115 -3.14991652796324136454E-11,
116 1.18891471078464383424E-11,
117 4.94060238822496958910E-10,
118 3.39623202570838634515E-9,
119 2.26666899049817806459E-8,
120 2.04891858946906374183E-7,
121 2.89137052083475648297E-6,
122 6.88975834691682398426E-5,
123 3.36911647825569408990E-3,
124 8.04490411014108831608E-1
125 };
126
127
128
129
130
131 private static final double[] A_i1 = {
132 2.77791411276104639959E-18,
133 -2.11142121435816608115E-17,
134 1.55363195773620046921E-16,
135 -1.10559694773538630805E-15,
136 7.60068429473540693410E-15,
137 -5.04218550472791168711E-14,
138 3.22379336594557470981E-13,
139 -1.98397439776494371520E-12,
140 1.17361862988909016308E-11,
141 -6.66348972350202774223E-11,
142 3.62559028155211703701E-10,
143 -1.88724975172282928790E-9,
144 9.38153738649577178388E-9,
145 -4.44505912879632808065E-8,
146 2.00329475355213526229E-7,
147 -8.56872026469545474066E-7,
148 3.47025130813767847674E-6,
149 -1.32731636560394358279E-5,
150 4.78156510755005422638E-5,
151 -1.61760815825896745588E-4,
152 5.12285956168575772895E-4,
153 -1.51357245063125314899E-3,
154 4.15642294431288815669E-3,
155 -1.05640848946261981558E-2,
156 2.47264490306265168283E-2,
157 -5.29459812080949914269E-2,
158 1.02643658689847095384E-1,
159 -1.76416518357834055153E-1,
160 2.52587186443633654823E-1
161 };
162
163
164
165
166
167 private static final double[] B_i1 = {
168 7.51729631084210481353E-18,
169 4.41434832307170791151E-18,
170 -4.65030536848935832153E-17,
171 -3.20952592199342395980E-17,
172 2.96262899764595013876E-16,
173 3.30820231092092828324E-16,
174 -1.88035477551078244854E-15,
175 -3.81440307243700780478E-15,
176 1.04202769841288027642E-14,
177 4.27244001671195135429E-14,
178 -2.10154184277266431302E-14,
179 -4.08355111109219731823E-13,
180 -7.19855177624590851209E-13,
181 2.03562854414708950722E-12,
182 1.41258074366137813316E-11,
183 3.25260358301548823856E-11,
184 -1.89749581235054123450E-11,
185 -5.58974346219658380687E-10,
186 -3.83538038596423702205E-9,
187 -2.63146884688951950684E-8,
188 -2.51223623787020892529E-7,
189 -3.88256480887769039346E-6,
190 -1.10588938762623716291E-4,
191 -9.76109749136146840777E-3,
192 7.78576235018280120474E-1
193 };
194
195
196
197
198
199
200
201
202
203
204 public static double i0(double x) {
205
206 if (Double.isNaN(x)) {
207 return Double.NaN;
208 }
209 if (Double.isInfinite(x)) {
210 return 0.0;
211 }
212
213 double y;
214 if (x < 0) {
215 x = -x;
216 }
217 if (x <= 8.0) {
218 y = (x * 0.5) - 2.0;
219 return (eToThe(x) * evaluateChebyshev(y, A_i0, 30));
220 }
221 double ix = 1.0 / x;
222 return (eToThe(x) * evaluateChebyshev(32.0 * ix - 2.0, B_i0, 25) * sqrt(ix));
223 }
224
225
226
227
228
229
230
231
232
233
234 public static double i1(double x) {
235
236 if (Double.isNaN(x)) {
237 return Double.NaN;
238 }
239 if (Double.isInfinite(x)) {
240 return 0.0;
241 }
242
243 double y, z;
244
245 z = abs(x);
246 if (z <= 8.0) {
247 y = (z * 0.5) - 2.0;
248 z = evaluateChebyshev(y, A_i1, 29) * z * eToThe(z);
249 } else {
250 double iz = 1.0 / z;
251 z = eToThe(z) * evaluateChebyshev(32.0 * iz - 2.0, B_i1, 25) * sqrt(iz);
252 }
253 if (x < 0.0) {
254 z = -z;
255 }
256 return (z);
257 }
258
259
260
261
262
263
264
265
266
267
268 public static double i1OverI0(double x) {
269
270 if (Double.isNaN(x)) {
271 return Double.NaN;
272 }
273 if (Double.isInfinite(x)) {
274 return 0.0;
275 }
276 if (x == 0.0) {
277 return 0.0;
278 }
279
280
281 if (abs(x) < 1.0) {
282 return i1(x) / i0(x);
283 }
284
285 double absX = abs(x);
286 double result;
287
288 if (absX <= 8.0) {
289
290 double y = (absX * 0.5) - 2.0;
291 double expX = eToThe(absX);
292 double i0Val = expX * evaluateChebyshev(y, A_i0, 30);
293 double i1Val = evaluateChebyshev(y, A_i1, 29) * absX * expX;
294 result = i1Val / i0Val;
295 } else {
296
297 double ix = 1.0 / absX;
298 double expX = eToThe(absX);
299 double sqrtIx = sqrt(ix);
300 double i0Val = expX * evaluateChebyshev(32.0 * ix - 2.0, B_i0, 25) * sqrtIx;
301 double i1Val = expX * evaluateChebyshev(32.0 * ix - 2.0, B_i1, 25) * sqrtIx;
302 result = i1Val / i0Val;
303 }
304
305
306 return (x < 0.0) ? -result : result;
307 }
308
309
310
311
312
313
314
315
316
317
318 public static double lnI0(double x) {
319
320 if (Double.isNaN(x)) {
321 return Double.NaN;
322 }
323 if (Double.isInfinite(x)) {
324 return Double.NEGATIVE_INFINITY;
325 }
326
327
328 if (abs(x) <= 8.0) {
329 double i0Val = i0(x);
330
331 return i0Val > 0.0 ? log(i0Val) : Double.NEGATIVE_INFINITY;
332 }
333
334
335 double absX = abs(x);
336 double ix = 1.0 / absX;
337
338
339
340 double chebyshevTerm = evaluateChebyshev(32.0 * ix - 2.0, B_i0, 25);
341
342
343 if (chebyshevTerm <= 0.0) {
344 return absX;
345 }
346
347 return absX + log(chebyshevTerm * sqrt(ix));
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362 private static double evaluateChebyshev(double x, double[] coefficients, int N) {
363 double b0, b1, b2;
364
365 int p = 0;
366 int i;
367
368 b0 = coefficients[p++];
369 b1 = 0.0;
370 i = N - 1;
371
372 do {
373 b2 = b1;
374 b1 = b0;
375 b0 = x * b1 - b2 + coefficients[p++];
376 } while (--i > 0);
377
378 return (0.5 * (b0 - b2));
379 }
380
381
382
383
384
385
386
387
388
389
390
391 private static double eToThe(double x) {
392
393 if (Double.isNaN(x)) {
394 return Double.NaN;
395 }
396
397
398 if (x > 709.0) {
399 return Double.MAX_VALUE;
400 }
401 if (x < -745.0) {
402 return Double.MIN_VALUE;
403 }
404
405 double res = exp(x);
406 if (res == Double.POSITIVE_INFINITY) {
407 return Double.MAX_VALUE;
408 } else if (res == Double.NEGATIVE_INFINITY || res == 0.0) {
409 return Double.MIN_VALUE;
410 }
411 return res;
412 }
413 }