1 /** 2 * Mathlib : A C Library of Special Functions 3 * Copyright (C) 1998-2014 Ross Ihaka and the R Core team. 4 * Copyright (C) 2002-3 The R Foundation 5 * Copyright (C) 2014-3 Ilya Yaroshenko (Ported to D) 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published b 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, a copy is available at 19 * http://www.r-project.org/Licenses/ 20 */ 21 22 module bessel; 23 24 static import std.math; 25 26 import core.stdc.stdlib; 27 import core.stdc.tgmath; 28 29 import std.algorithm; 30 import std.exception; 31 import std.string; 32 import std.traits; 33 import std.typecons; 34 35 /* Documentation that apply to several of the bessel[IJKY] functions */ 36 37 /* ******************************************************************* 38 39 Explanation of machine-dependent constants 40 41 beta = Radix for the floating-point system 42 minexp = Smallest representable power of beta 43 maxexp = Smallest power of beta that overflows 44 it = p = Number of bits (base-beta digits) in the mantissa 45 (significand) of a working precision (floating-point) variable 46 NSIG = Decimal significance desired. Should be set to 47 INT(LOG10(2)*it+1). Setting NSIG lower will result 48 in decreased accuracy while setting NSIG higher will 49 increase CPU time without increasing accuracy. The 50 truncation error is limited to a relative error of 51 T=.5*10^(-NSIG). 52 ENTEN = 10 ^ K, where K is the largest int such that 53 ENTEN is machine-representable in working precision 54 ENSIG = 10 ^ NSIG 55 RTNSIG = 10 ^ (-K) for the smallest int K such that K >= NSIG/4 56 ENMTEN = Smallest ABS(X) such that X/4 does not underflow 57 XINF = Largest positive machine number; approximately beta ^ maxexp 58 == double.max (defined in #include <float.h>) 59 SQXMIN = Square root of beta ^ minexp = sqrt(double.min_normal) 60 61 EPS = The smallest positive floating-point number such that 1.0+EPS > 1.0 62 = beta ^ (-p) == double.epsilon 63 64 65 For I : 66 67 EXPARG = Largest working precision argument that the liaary 68 EXP routine can handle and upper limit on the 69 magnitude of X when IZE=1; approximately LOG(beta ^ maxexp) 70 71 For I and J : 72 73 xlrg_IJ = xlrg_BESS_IJ (was = XLARGE). Upper limit on the magnitude of X 74 (when IZE=2 for I()). Bear in mind that if floor(abs(x)) =: N, then 75 at least N iterations of the backward recursion will be executed. 76 The value of 10 ^ 4 was used till Feb.2009, when it was increased 77 to 10 ^ 5 (= 1e5). 78 79 For j : 80 XMIN_J = Smallest acceptable argument for RBESY; approximately 81 max(2*beta ^ minexp, 2/XINF), rounded up 82 83 For Y : 84 85 xlrg_Y = (was = XLARGE). Upper bound on X; 86 approximately 1/DEL, because the sine and cosine functions 87 have lost about half of their precision at that point. 88 89 EPS_SINC = Machine number below which sin(x)/x = 1; approximately SQRT(EPS). 90 THRESH = Lower bound for use of the asymptotic form; 91 approximately AINT(-LOG10(EPS/2.0))+1.0 92 93 94 For K : 95 96 xmax_k = (was = XMAX). Upper limit on the magnitude of X when ize = 1; 97 i.e. maximal x for UNscaled answer. 98 99 Solution to equation: 100 W(X) * (1 -1/8 X + 9/128 X^2) = beta ^ minexp 101 where W(X) = EXP(-X)*SQRT(PI/2X) 102 103 -------------------------------------------------------------------- 104 105 Approximate values for some important machines are: 106 107 beta minexp maxexp it NSIG ENTEN ENSIG RTNSIG ENMTEN EXPARG 108 IEEE (IBM/XT, 109 SUN, etc.) (S.P.) 2 -126 128 24 8 1e38 1e8 1e-2 4.70e-38 88 110 IEEE (...) (D.P.) 2 -1022 1024 53 16 1e308 1e16 1e-4 8.90e-308 709 111 CRAY-1 (S.P.) 2 -8193 8191 48 15 1e2465 1e15 1e-4 1.84e-2466 5677 112 Cyber 180/855 113 under NOS (S.P.) 2 -975 1070 48 15 1e322 1e15 1e-4 1.25e-293 741 114 IBM 3033 (D.P.) 16 -65 63 14 5 1e75 1e5 1e-2 2.16e-78 174 115 VAX (S.P.) 2 -128 127 24 8 1e38 1e8 1e-2 1.17e-38 88 116 VAX D-Format (D.P.) 2 -128 127 56 17 1e38 1e17 1e-5 1.17e-38 88 117 VAX G-Format (D.P.) 2 -1024 1023 53 16 1e307 1e16 1e-4 2.22e-308 709 118 119 120 And routine specific : 121 122 xlrg_IJ xlrg_Y xmax_k EPS_SINC XMIN_J XINF THRESH 123 IEEE (IBM/XT, 124 SUN, etc.) (S.P.) 1e4 1e4 85.337 1e-4 2.36e-38 3.40e38 8. 125 IEEE (...) (D.P.) 1e4 1e8 705.342 1e-8 4.46e-308 1.79e308 16. 126 CRAY-1 (S.P.) 1e4 2e7 5674.858 5e-8 3.67e-2466 5.45e2465 15. 127 Cyber 180/855 128 under NOS (S.P.) 1e4 2e7 672.788 5e-8 6.28e-294 1.26e322 15. 129 IBM 3033 (D.P.) 1e4 1e8 177.852 1e-8 2.77e-76 7.23e75 17. 130 VAX (S.P.) 1e4 1e4 86.715 1e-4 1.18e-38 1.70e38 8. 131 VAX e-Format (D.P.) 1e4 1e9 86.715 1e-9 1.18e-38 1.70e38 17. 132 VAX G-Format (D.P.) 1e4 1e8 706.728 1e-8 2.23e-308 8.98e307 16. 133 134 */ 135 private enum double nsig_BESS = 16; 136 private enum double ensig_BESS = 1e16; 137 private enum double rtnsig_BESS = 1e-4; 138 private enum double enmten_BESS = 8.9e-308; 139 private enum double enten_BESS = 1e308; 140 141 private enum double exparg_BESS = 709.; 142 private enum double xlrg_BESS_IJ = 1e5; 143 private enum double xlrg_BESS_Y = 1e8; 144 private enum double thresh_BESS_Y = 16.; 145 146 private enum double xmax_BESS_K = 705.342/* maximal x for UNscaled answer */; 147 148 149 /* sqrt(double.min_normal) = 1.491668e-154 */ 150 private enum double sqxmin_BESS_K = 1.49e-154; 151 152 /* x < eps_sinc <==> sin(x)/x == 1 (particularly "==>"); 153 Linux (around 2001-02) gives 2.14946906753213e-08 154 Solaris 2.5.1 gives 2.14911933289084e-08 155 */ 156 private enum double M_eps_sinc = 2.149e-8; 157 158 private enum double M_SQRT_2dPI = 0.797884560802865355879892119869; 159 160 161 /// 162 double besselK(double x, double alpha, Flag!"ExponentiallyScaled" expFlag = Flag!"ExponentiallyScaled".no) 163 { 164 ptrdiff_t nb; 165 ptrdiff_t ncalc; 166 double* b; 167 168 /* NaNs propagated correctly */ 169 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 170 return x + alpha; 171 if (x < 0) 172 return double.nan; 173 if(alpha < 0) 174 alpha = -alpha; 175 nb = 1 + cast(int)floor(alpha);/* b.length-1 <= |alpha| < b.length */ 176 alpha -= nb-1; 177 b = cast(double*) calloc(nb, double.sizeof).enforce("besselK allocation error"); 178 besselK(x, alpha, expFlag, b[0..nb], ncalc); 179 if(ncalc != nb) {/* error input */ 180 if(ncalc < 0) 181 throw new Exception(format("besselK(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 182 x, ncalc, nb, alpha)); 183 else 184 throw new Exception(format("besselK(%g,nu=%g): precision lost in result\n", 185 x, alpha+(nb-1))); 186 } 187 x = b[nb-1]; 188 free(b); 189 return x; 190 } 191 192 /// 193 unittest { 194 assert(std.math.approxEqual(besselK(2, 1), 0.139865881816522427284)); 195 assert(std.math.approxEqual(besselK(20, 1), 5.88305796955703817765028e-10)); 196 assert(std.math.approxEqual(besselK(1, 1.2), 0.701080)); 197 } 198 199 /* modified version of besselK that accepts a work array instead of 200 allocating one. */ 201 double besselK(double x, double alpha, Flag!"ExponentiallyScaled" expFlag, double[] b) 202 { 203 ptrdiff_t nb; 204 ptrdiff_t ncalc; 205 206 /* NaNs propagated correctly */ 207 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 208 return x + alpha; 209 if (x < 0) 210 return double.nan; 211 if(alpha < 0) 212 alpha = -alpha; 213 nb = 1+cast(int)floor(alpha);/* b.length-1 <= |alpha| < b.length */ 214 alpha -= nb-1; 215 besselK(x, alpha, expFlag, b[0..nb], ncalc); 216 if(ncalc != nb) {/* error input */ 217 if(ncalc < 0) 218 throw new Exception(format("besselK(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 219 x, ncalc, nb, alpha)); 220 else 221 throw new Exception(format("besselK(%g,nu=%g): precision lost in result\n", 222 x, alpha+(nb-1))); 223 } 224 x = b[nb-1]; 225 return x; 226 } 227 228 void besselK(double x, double alpha, Flag!"ExponentiallyScaled" expFlag, double[] b, ref ptrdiff_t ncalc) 229 { 230 /*------------------------------------------------------------------- 231 232 This routine calculates modified Bessel functions 233 of the third kind, K_(N+ALPHA) (X), for non-negative 234 argument X, and non-negative order N+ALPHA, with or without 235 exponential scaling. 236 237 Explanation of variables in the calling sequence 238 239 X - Non-negative argument for which 240 K's or exponentially scaled K's (K*EXP(X)) 241 are to be calculated. If K's are to be calculated, 242 X must not be greater than XMAX_BESS_K. 243 ALPHA - Fractional part of order for which 244 K's or exponentially scaled K's (K*EXP(X)) are 245 to be calculated. 0 <= ALPHA < 1.0. 246 NB - Number of functions to be calculated, NB > 0. 247 The first function calculated is of order ALPHA, and the 248 last is of order (NB - 1 + ALPHA). 249 expFlag - Type. expFlag = No if unscaled K's are to be calculated, 250 = Yes if exponentially scaled K's are to be calculated. 251 BK - Output vector of length NB. If the 252 routine terminates normally (NCALC=NB), the vector BK 253 contains the functions K(ALPHA,X), ... , K(NB-1+ALPHA,X), 254 or the corresponding exponentially scaled functions. 255 If (0 < NCALC < NB), BK(I) contains correct function 256 values for I <= NCALC, and contains the ratios 257 K(ALPHA+I-1,X)/K(ALPHA+I-2,X) for the rest of the array. 258 NCALC - Output variable indicating possible errors. 259 Before using the vector BK, the user should check that 260 NCALC=NB, i.e., all orders have been calculated to 261 the desired accuracy. See error returns below. 262 263 264 ******************************************************************* 265 266 Error returns 267 268 In case of an error, NCALC != NB, and not all K's are 269 calculated to the desired accuracy. 270 271 NCALC < -1: An argument is out of range. For example, 272 NB <= 0, IZE is not 1 or 2, or IZE=1 and ABS(X) >= XMAX_BESS_K. 273 In this case, the B-vector is not calculated, 274 and NCALC is set to MIN0(NB,0)-2 so that NCALC != NB. 275 NCALC = -1: Either K(ALPHA,X) >= XINF or 276 K(ALPHA+NB-1,X)/K(ALPHA+NB-2,X) >= XINF. In this case, 277 the B-vector is not calculated. Note that again 278 NCALC != NB. 279 280 0 < NCALC < NB: Not all requested function values could 281 be calculated accurately. BK(I) contains correct function 282 values for I <= NCALC, and contains the ratios 283 K(ALPHA+I-1,X)/K(ALPHA+I-2,X) for the rest of the array. 284 285 286 Intrinsic functions required are: 287 288 ABS, AINT, EXP, INT, LOG, MAX, MIN, SINH, SQRT 289 290 291 Acknowledgement 292 293 This program is based on a program written b J. B. Campbell 294 (2) that computes values of the Bessel functions K of float 295 argument and float order. Modifications include the addition 296 of non-scaled functions, parameterization of machine 297 dependencies, and the use of more accurate approximations 298 for SINH and SIN. 299 300 References: "On Temme's Algorithm for the Modified Bessel 301 Functions of the Third Kind," Campbell, J. B., 302 TOMS 6(4), Dec. 1980, pp. 581-586. 303 304 "A FORTRAN IV Suaoutine for the Modified Bessel 305 Functions of the Third Kind of Real Order and Real 306 Argument," Campbell, J. B., Report NRC/ERB-925, 307 National Research Council, Canada. 308 309 Latest modification: May 30, 1989 310 311 Modified b: W. J. Cody and L. Stoltz 312 Applied Mathematics Division 313 Argonne National Laboratory 314 Argonne, IL 60439 315 316 ------------------------------------------------------------------- 317 */ 318 /*--------------------------------------------------------------------- 319 * Mathematical constants 320 * A = LOG(2) - Euler's constant 321 * D = SQRT(2/PI) 322 ---------------------------------------------------------------------*/ 323 static immutable double a = .11593151565841244881; 324 325 /*--------------------------------------------------------------------- 326 P, Q - Approximation for LOG(GAMMA(1+ALPHA))/ALPHA + Euler's constant 327 Coefficients converted from hex to decimal and modified 328 b W. J. Cody, 2/26/82 */ 329 static immutable double[8] p = [ .805629875690432845,20.4045500205365151, 330 157.705605106676174,536.671116469207504,900.382759291288778, 331 730.923886650660393,229.299301509425145,.822467033424113231 ]; 332 static immutable double[7] q = [ 29.4601986247850434,277.577868510221208, 333 1206.70325591027438,2762.91444159791519,3443.74050506564618, 334 2210.63190113378647,572.267338359892221 ]; 335 /* R, S - Approximation for (1-ALPHA*PI/SIN(ALPHA*PI))/(2.D0*ALPHA) */ 336 static immutable double[5] r = [ -.48672575865218401848,13.079485869097804016, 337 -101.96490580880537526,347.65409106507813131, 338 3.495898124521934782e-4 ]; 339 static immutable double[4] s = [ -25.579105509976461286,212.57260432226544008, 340 -610.69018684944109624,422.69668805777760407 ]; 341 /* T - Approximation for SINH(Y)/Y */ 342 static immutable double[6] t = [ 1.6125990452916363814e-10, 343 2.5051878502858255354e-8,2.7557319615147964774e-6, 344 1.9841269840928373686e-4,.0083333333333334751799, 345 .16666666666666666446 ]; 346 /*---------------------------------------------------------------------*/ 347 static immutable double estm[6] = [ 52.0583,5.7607,2.7782,14.4303,185.3004, 9.3715 ]; 348 static immutable double estf[7] = [ 41.8341,7.1075,6.4306,42.511,1.35633,84.5096,20.]; 349 350 /* Local variables */ 351 ptrdiff_t iend, i, j, k, m, ii, mplus1; 352 double x2b4, twox, c, blpha, ratio, wminf; 353 double d1, d2, d3, f0, f1, f2, p0, q0, t1, t2, twonu; 354 double dm, ex, b1, b2, nu; 355 356 ii = 0; /* -Wall */ 357 358 ex = x; 359 nu = alpha; 360 ncalc = -2; 361 if (b.length > 0 && (0. <= nu && nu < 1.)) { 362 if(ex <= 0 || (expFlag == false && ex > xmax_BESS_K)) { 363 if(ex <= 0) { 364 enforce(ex == 0, "besselK Range Error"); 365 for(i=0; i < b.length; i++) 366 b[i] = double.infinity; 367 } else /* would only have underflow */ 368 for(i=0; i < b.length; i++) 369 b[i] = 0; 370 ncalc = b.length; 371 return; 372 } 373 k = 0; 374 if (nu < sqxmin_BESS_K) { 375 nu = 0; 376 } else if (nu > .5) { 377 k = 1; 378 nu -= 1.; 379 } 380 twonu = nu + nu; 381 iend = b.length + k - 1; 382 c = nu * nu; 383 d3 = -c; 384 if (ex <= 1.) { 385 /* ------------------------------------------------------------ 386 Calculation of P0 = GAMMA(1+ALPHA) * (2/X)**ALPHA 387 Q0 = GAMMA(1-ALPHA) * (X/2)**ALPHA 388 ------------------------------------------------------------ */ 389 d1 = 0; d2 = p[0]; 390 t1 = 1.; t2 = q[0]; 391 for (i = 2; i <= 7; i += 2) { 392 d1 = c * d1 + p[i - 1]; 393 d2 = c * d2 + p[i]; 394 t1 = c * t1 + q[i - 1]; 395 t2 = c * t2 + q[i]; 396 } 397 d1 = nu * d1; 398 t1 = nu * t1; 399 f1 = log(ex); 400 f0 = a + nu * (p[7] - nu * (d1 + d2) / (t1 + t2)) - f1; 401 q0 = exp(-nu * (a - nu * (p[7] + nu * (d1-d2) / (t1-t2)) - f1)); 402 f1 = nu * f0; 403 p0 = exp(f1); 404 /* ----------------------------------------------------------- 405 Calculation of F0 = 406 ----------------------------------------------------------- */ 407 d1 = r[4]; 408 t1 = 1.; 409 for (i = 0; i < 4; ++i) { 410 d1 = c * d1 + r[i]; 411 t1 = c * t1 + s[i]; 412 } 413 /* d2 := sinh(f1)/ nu = sinh(f1)/(f1/f0) 414 * = f0 * sinh(f1)/f1 */ 415 if (fabs(f1) <= .5) { 416 f1 *= f1; 417 d2 = 0; 418 for (i = 0; i < 6; ++i) { 419 d2 = f1 * d2 + t[i]; 420 } 421 d2 = f0 + f0 * f1 * d2; 422 } else { 423 d2 = sinh(f1) / nu; 424 } 425 f0 = d2 - nu * d1 / (t1 * p0); 426 if (ex <= 1e-10) { 427 /* --------------------------------------------------------- 428 X <= 1.0E-10 429 Calculation of K(ALPHA,X) and X*K(ALPHA+1,X)/K(ALPHA,X) 430 --------------------------------------------------------- */ 431 b[0] = f0 + ex * f0; 432 if (expFlag == false) { 433 b[0] -= ex * b[0]; 434 } 435 ratio = p0 / f0; 436 c = ex * double.max; 437 if (k != 0) { 438 /* --------------------------------------------------- 439 Calculation of K(ALPHA,X) 440 and X*K(ALPHA+1,X)/K(ALPHA,X), ALPHA >= 1/2 441 --------------------------------------------------- */ 442 ncalc = -1; 443 if (b[0] >= c / ratio) { 444 return; 445 } 446 b[0] = ratio * b[0] / ex; 447 twonu += 2.; 448 ratio = twonu; 449 } 450 ncalc = 1; 451 if (b.length == 1) 452 return; 453 454 /* ----------------------------------------------------- 455 Calculate K(ALPHA+L,X)/K(ALPHA+L-1,X), 456 L = 1, 2, ... , NB-1 457 ----------------------------------------------------- */ 458 ncalc = -1; 459 for (i = 1; i < b.length; ++i) { 460 if (ratio >= c) 461 return; 462 463 b[i] = ratio / ex; 464 twonu += 2.; 465 ratio = twonu; 466 } 467 ncalc = 1; 468 goto L420; 469 } else { 470 /* ------------------------------------------------------ 471 10^-10 < X <= 1.0 472 ------------------------------------------------------ */ 473 c = 1.; 474 x2b4 = ex * ex / 4.; 475 p0 = .5 * p0; 476 q0 = .5 * q0; 477 d1 = -1.; 478 d2 = 0; 479 b1 = 0; 480 b2 = 0; 481 f1 = f0; 482 f2 = p0; 483 do { 484 d1 += 2.; 485 d2 += 1.; 486 d3 = d1 + d3; 487 c = x2b4 * c / d2; 488 f0 = (d2 * f0 + p0 + q0) / d3; 489 p0 /= d2 - nu; 490 q0 /= d2 + nu; 491 t1 = c * f0; 492 t2 = c * (p0 - d2 * f0); 493 b1 += t1; 494 b2 += t2; 495 } while (fabs(t1 / (f1 + b1)) > double.epsilon || 496 fabs(t2 / (f2 + b2)) > double.epsilon); 497 b1 = f1 + b1; 498 b2 = 2. * (f2 + b2) / ex; 499 if (expFlag) { 500 d1 = exp(ex); 501 b1 *= d1; 502 b2 *= d1; 503 } 504 wminf = estf[0] * ex + estf[1]; 505 } 506 } else if (double.epsilon * ex > 1.) { 507 /* ------------------------------------------------- 508 X > 1./EPS 509 ------------------------------------------------- */ 510 ncalc = b.length; 511 b1 = 1. / (M_SQRT_2dPI * sqrt(ex)); 512 for (i = 0; i < b.length; ++i) 513 b[i] = b1; 514 return; 515 516 } else { 517 /* ------------------------------------------------------- 518 X > 1.0 519 ------------------------------------------------------- */ 520 twox = ex + ex; 521 blpha = 0; 522 ratio = 0; 523 if (ex <= 4.) { 524 /* ---------------------------------------------------------- 525 Calculation of K(ALPHA+1,X)/K(ALPHA,X), 1.0 <= X <= 4.0 526 ----------------------------------------------------------*/ 527 d2 = trunc(estm[0] / ex + estm[1]); 528 m = cast(int) d2; 529 d1 = d2 + d2; 530 d2 -= .5; 531 d2 *= d2; 532 for (i = 2; i <= m; ++i) { 533 d1 -= 2.; 534 d2 -= d1; 535 ratio = (d3 + d2) / (twox + d1 - ratio); 536 } 537 /* ----------------------------------------------------------- 538 Calculation of I(|ALPHA|,X) and I(|ALPHA|+1,X) by backward 539 recurrence and K(ALPHA,X) from the wronskian 540 -----------------------------------------------------------*/ 541 d2 = trunc(estm[2] * ex + estm[3]); 542 m = cast(int) d2; 543 c = fabs(nu); 544 d3 = c + c; 545 d1 = d3 - 1.; 546 f1 = double.min_normal; 547 f0 = (2. * (c + d2) / ex + .5 * ex / (c + d2 + 1.)) * double.min_normal; 548 for (i = 3; i <= m; ++i) { 549 d2 -= 1.; 550 f2 = (d3 + d2 + d2) * f0; 551 blpha = (1. + d1 / d2) * (f2 + blpha); 552 f2 = f2 / ex + f1; 553 f1 = f0; 554 f0 = f2; 555 } 556 f1 = (d3 + 2.) * f0 / ex + f1; 557 d1 = 0; 558 t1 = 1.; 559 for (i = 1; i <= 7; ++i) { 560 d1 = c * d1 + p[i - 1]; 561 t1 = c * t1 + q[i - 1]; 562 } 563 p0 = exp(c * (a + c * (p[7] - c * d1 / t1) - log(ex))) / ex; 564 f2 = (c + .5 - ratio) * f1 / ex; 565 b1 = p0 + (d3 * f0 - f2 + f0 + blpha) / (f2 + f1 + f0) * p0; 566 if (expFlag == false) { 567 b1 *= exp(-ex); 568 } 569 wminf = estf[2] * ex + estf[3]; 570 } else { 571 /* --------------------------------------------------------- 572 Calculation of K(ALPHA,X) and K(ALPHA+1,X)/K(ALPHA,X), by 573 backward recurrence, for X > 4.0 574 ----------------------------------------------------------*/ 575 dm = trunc(estm[4] / ex + estm[5]); 576 m = cast(int) dm; 577 d2 = dm - .5; 578 d2 *= d2; 579 d1 = dm + dm; 580 for (i = 2; i <= m; ++i) { 581 dm -= 1.; 582 d1 -= 2.; 583 d2 -= d1; 584 ratio = (d3 + d2) / (twox + d1 - ratio); 585 blpha = (ratio + ratio * blpha) / dm; 586 } 587 b1 = 1. / ((M_SQRT_2dPI + M_SQRT_2dPI * blpha) * sqrt(ex)); 588 if (expFlag == false) 589 b1 *= exp(-ex); 590 wminf = estf[4] * (ex - fabs(ex - estf[6])) + estf[5]; 591 } 592 /* --------------------------------------------------------- 593 Calculation of K(ALPHA+1,X) 594 from K(ALPHA,X) and K(ALPHA+1,X)/K(ALPHA,X) 595 --------------------------------------------------------- */ 596 b2 = b1 + b1 * (nu + .5 - ratio) / ex; 597 } 598 /*-------------------------------------------------------------------- 599 Calculation of 'NCALC', K(ALPHA+I,X), I = 0, 1, ... , NCALC-1, 600 & K(ALPHA+I,X)/K(ALPHA+I-1,X), I = NCALC, NCALC+1, ... , NB-1 601 -------------------------------------------------------------------*/ 602 ncalc = b.length; 603 b[0] = b1; 604 if (iend == 0) 605 return; 606 607 j = 1 - k; 608 if (j >= 0) 609 b[j] = b2; 610 611 if (iend == 1) 612 return; 613 614 m = min(cast(int) (wminf - nu),iend); 615 for (i = 2; i <= m; ++i) { 616 t1 = b1; 617 b1 = b2; 618 twonu += 2.; 619 if (ex < 1.) { 620 if (b1 >= double.max / twonu * ex) 621 break; 622 } else { 623 if (b1 / ex >= double.max / twonu) 624 break; 625 } 626 b2 = twonu / ex * b1 + t1; 627 ii = i; 628 ++j; 629 if (j >= 0) { 630 b[j] = b2; 631 } 632 } 633 634 m = ii; 635 if (m == iend) { 636 return; 637 } 638 ratio = b2 / b1; 639 mplus1 = m + 1; 640 ncalc = -1; 641 for (i = mplus1; i <= iend; ++i) { 642 twonu += 2.; 643 ratio = twonu / ex + 1./ratio; 644 ++j; 645 if (j >= 1) { 646 b[j] = ratio; 647 } else { 648 if (b2 >= double.max / ratio) 649 return; 650 651 b2 *= ratio; 652 } 653 } 654 ncalc = max(1, mplus1 - k); 655 if (ncalc == 1) 656 b[0] = b2; 657 if (b.length == 1) 658 return; 659 660 L420: 661 for (i = ncalc; i < b.length; ++i) { /* i == ncalc */ 662 if (b[i-1] >= double.max / b[i]) 663 return; 664 b[i] *= b[i-1]; 665 ncalc++; 666 } 667 } 668 } 669 670 671 /// 672 double besselI(double x, double alpha, Flag!"ExponentiallyScaled" expFlag = Flag!"ExponentiallyScaled".no) 673 { 674 ptrdiff_t nb; 675 ptrdiff_t ncalc; 676 double na; 677 double* b; 678 679 /* NaNs propagated correctly */ 680 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 681 return x + alpha; 682 if (x < 0) 683 return double.nan; 684 na = floor(alpha); 685 if (alpha < 0) { 686 /* Using Aaamowitz & Stegun 9.6.2 & 9.6.6 687 * this may not be quite optimal (CPU and accuracy wise) */ 688 return(besselI(x, -alpha, expFlag) + 689 ((alpha == na) ? /* sin(pi * alpha) = 0 */ 0 : 690 besselK(x, -alpha, expFlag) * 691 (expFlag == true ? 2. : 2.*exp(-2.0 * x)) / cast(double) std.math.PI * sinPi(-alpha))); 692 } 693 nb = 1 + cast(int)na;/* b.length-1 <= alpha < b.length */ 694 alpha -= nb-1; 695 b = cast(double*) calloc(nb, double.sizeof).enforce("besselI allocation error"); 696 besselI(x, alpha, expFlag, b[0..nb], ncalc); 697 if(ncalc != nb) {/* error input */ 698 if(ncalc < 0) 699 throw new Exception(format("besselI(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 700 x, ncalc, nb, alpha)); 701 else 702 throw new Exception(format("besselI(%g,nu=%g): precision lost in result\n", 703 x, alpha+(nb-1))); 704 } 705 x = b[nb-1]; 706 free(b); 707 return x; 708 } 709 710 /// 711 unittest { 712 assert(std.math.approxEqual(besselI(2, 1), 1.590636854637329063382254424999666)); 713 assert(std.math.approxEqual(besselI(20, 1), 4.245497338512777018140990665e+7)); 714 assert(std.math.approxEqual(besselI(1, 1.2), 0.441739)); 715 } 716 717 718 /* modified version of besselI that accepts a work array instead of 719 allocating one. */ 720 double besselI(double x, double alpha, Flag!"ExponentiallyScaled" expFlag, double[] b) 721 { 722 ptrdiff_t nb; 723 ptrdiff_t ncalc; 724 double na; 725 726 /* NaNs propagated correctly */ 727 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 728 return x + alpha; 729 if (x < 0) 730 return double.nan; 731 na = floor(alpha); 732 if (alpha < 0) { 733 /* Using Aaamowitz & Stegun 9.6.2 & 9.6.6 734 * this may not be quite optimal (CPU and accuracy wise) */ 735 return(besselI(x, -alpha, expFlag, b) + 736 ((alpha == na) ? 0 : 737 besselK(x, -alpha, expFlag, b) * 738 (expFlag == true ? 2. : 2.*exp(-2.0 * x))/cast(double)std.math.PI * sinPi(-alpha))); 739 } 740 nb = 1 + cast(int)na;/* b.length-1 <= alpha < b.length */ 741 alpha -= nb-1; 742 besselI(x, alpha, expFlag, b[0..nb], ncalc); 743 if(ncalc != nb) {/* error input */ 744 if(ncalc < 0) 745 throw new Exception(format("besselI(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 746 x, ncalc, nb, alpha)); 747 else 748 throw new Exception(format("besselI(%g,nu=%g): precision lost in result\n", 749 x, alpha+(nb-1))); 750 } 751 x = b[nb-1]; 752 return x; 753 } 754 755 void besselI(double x, double alpha, Flag!"ExponentiallyScaled" expFlag, double[] b, ref ptrdiff_t ncalc) 756 { 757 /* ------------------------------------------------------------------- 758 759 This routine calculates Bessel functions I_(N+ALPHA) (X) 760 for non-negative argument X, and non-negative order N+ALPHA, 761 with or without exponential scaling. 762 763 764 Explanation of variables in the calling sequence 765 766 X - Non-negative argument for which 767 I's or exponentially scaled I's (I*EXP(-X)) 768 are to be calculated. If I's are to be calculated, 769 X must be less than exparg_BESS (IZE=1) or xlrg_BESS_IJ (IZE=2), 770 (see bessel.h). 771 ALPHA - Fractional part of order for which 772 I's or exponentially scaled I's (I*EXP(-X)) are 773 to be calculated. 0 <= ALPHA < 1.0. 774 NB - Number of functions to be calculated, NB > 0. 775 The first function calculated is of order ALPHA, and the 776 last is of order (NB - 1 + ALPHA). 777 IZE - Type. IZE = 1 if unscaled I's are to be calculated, 778 = 2 if exponentially scaled I's are to be calculated. 779 BI - Output vector of length NB. If the routine 780 terminates normally (NCALC=NB), the vector BI contains the 781 functions I(ALPHA,X) through I(NB-1+ALPHA,X), or the 782 corresponding exponentially scaled functions. 783 NCALC - Output variable indicating possible errors. 784 Before using the vector BI, the user should check that 785 NCALC=NB, i.e., all orders have been calculated to 786 the desired accuracy. See error returns below. 787 788 789 ******************************************************************* 790 ******************************************************************* 791 792 Error returns 793 794 In case of an error, NCALC != NB, and not all I's are 795 calculated to the desired accuracy. 796 797 NCALC < 0: An argument is out of range. For example, 798 NB <= 0, IZE is not 1 or 2, or IZE=1 and ABS(X) >= EXPARG_BESS. 799 In this case, the BI-vector is not calculated, and NCALC is 800 set to MIN0(NB,0)-1 so that NCALC != NB. 801 802 NB > NCALC > 0: Not all requested function values could 803 be calculated accurately. This usually occurs because NB is 804 much larger than ABS(X). In this case, BI[N] is calculated 805 to the desired accuracy for N <= NCALC, but precision 806 is lost for NCALC < N <= NB. If BI[N] does not vanish 807 for N > NCALC (because it is too small to be represented), 808 and BI[N]/BI[NCALC] = 10**(-K), then only the first NSIG-K 809 significant figures of BI[N] can be trusted. 810 811 812 Intrinsic functions required are: 813 814 DBLE, EXP, gamma_cody, INT, MAX, MIN, REAL, SQRT 815 816 817 Acknowledgement 818 819 This program is based on a program written b David J. 820 Sookne (2) that computes values of the Bessel functions J or 821 I of float argument and long order. Modifications include 822 the restriction of the computation to the I Bessel function 823 of non-negative float argument, the extension of the computation 824 to arbtrary positive order, the inclusion of optional 825 exponential scaling, and the elimination of most underflow. 826 An earlier version was published in (3). 827 828 References: "A Note on Backward Recurrence Algorithms," Olver, 829 F. W. J., and Sookne, D. J., Math. Comp. 26, 1972, 830 pp 941-947. 831 832 "Bessel Functions of Real Argument and Integer Order," 833 Sookne, D. J., NBS Jour. of Res. B. 77B, 1973, pp 834 125-132. 835 836 "ALGORITHM 597, Sequence of Modified Bessel Functions 837 of the First Kind," Cody, W. J., Trans. Math. Soft., 838 1983, pp. 242-245. 839 840 Latest modification: May 30, 1989 841 842 Modified b: W. J. Cody and L. Stoltz 843 Applied Mathematics Division 844 Argonne National Laboratory 845 Argonne, IL 60439 846 */ 847 848 /*------------------------------------------------------------------- 849 Mathematical constants 850 -------------------------------------------------------------------*/ 851 enum double const__ = 1.585; 852 853 /* Local variables */ 854 ptrdiff_t nend, intx, nbmx, k, l, n, nstart; 855 double pold, test, p, em, en, empal, emp2al, halfx, 856 aa, bb, cc, psave, plast, tover, psavel, sum, nu, twonu; 857 858 /*Parameter adjustments */ 859 // --b; 860 nu = alpha; 861 twonu = nu + nu; 862 863 /*------------------------------------------------------------------- 864 Check for X, NB, OR IZE out of range. 865 ------------------------------------------------------------------- */ 866 if (b.length > 0 && x >= 0. && (0. <= nu && nu < 1.) ) { 867 868 ncalc = b.length; 869 if(expFlag == false && x > exparg_BESS) { 870 b[] = double.infinity; /* the limit *is* = Inf */ 871 return; 872 } 873 if(expFlag && x > xlrg_BESS_IJ) { 874 b[] = 0; /* The limit exp(-x) * I_nu(x) --> 0 : */ 875 return; 876 } 877 intx = cast(int) (x);/* fine, since x <= xlrg_BESS_IJ <<< LONG_MAX */ 878 if (x >= rtnsig_BESS) { /* "non-small" x ( >= 1e-4 ) */ 879 /* ------------------------------------------------------------------- 880 Initialize the forward sweep, the P-sequence of Olver 881 ------------------------------------------------------------------- */ 882 nbmx = b.length - intx; 883 n = intx + 1; 884 en = cast(double) (n + n) + twonu; 885 plast = 1.; 886 p = en / x; 887 /* ------------------------------------------------ 888 Calculate general significance test 889 ------------------------------------------------ */ 890 test = ensig_BESS + ensig_BESS; 891 if (intx << 1 > nsig_BESS * 5) { 892 test = sqrt(test * p); 893 } else { 894 test /= const__ ^^ intx; 895 } 896 if (nbmx >= 3) { 897 /* -------------------------------------------------- 898 Calculate P-sequence until N = NB-1 899 Check for possible overflow. 900 ------------------------------------------------ */ 901 tover = enten_BESS / ensig_BESS; 902 nstart = intx + 2; 903 nend = b.length - 1; 904 for (k = nstart; k <= nend; ++k) { 905 n = k; 906 en += 2.; 907 pold = plast; 908 plast = p; 909 p = en * plast / x + pold; 910 if (p > tover) { 911 /* ------------------------------------------------ 912 To avoid overflow, divide P-sequence b TOVER. 913 Calculate P-sequence until ABS(P) > 1. 914 ---------------------------------------------- */ 915 tover = enten_BESS; 916 p /= tover; 917 plast /= tover; 918 psave = p; 919 psavel = plast; 920 nstart = n + 1; 921 do { 922 ++n; 923 en += 2.; 924 pold = plast; 925 plast = p; 926 p = en * plast / x + pold; 927 } 928 while (p <= 1.); 929 930 bb = en / x; 931 /* ------------------------------------------------ 932 Calculate backward test, and find NCALC, 933 the highest N such that the test is passed. 934 ------------------------------------------------ */ 935 test = pold * plast / ensig_BESS; 936 test *= .5 - .5 / (bb * bb); 937 p = plast * tover; 938 --n; 939 en -= 2.; 940 nend = min(b.length,n); 941 for (l = nstart; l <= nend; ++l) { 942 ncalc = l; 943 pold = psavel; 944 psavel = psave; 945 psave = en * psavel / x + pold; 946 if (psave * psavel > test) { 947 goto L90; 948 } 949 } 950 ncalc = nend + 1; 951 L90: 952 ncalc--; 953 goto L120; 954 } 955 } 956 n = nend; 957 en = cast(double)(n + n) + twonu; 958 /*--------------------------------------------------- 959 Calculate special significance test for NBMX > 2. 960 --------------------------------------------------- */ 961 test = max(test, sqrt(plast * ensig_BESS) * sqrt(p + p)); 962 } 963 /* -------------------------------------------------------- 964 Calculate P-sequence until significance test passed. 965 -------------------------------------------------------- */ 966 do { 967 ++n; 968 en += 2.; 969 pold = plast; 970 plast = p; 971 p = en * plast / x + pold; 972 } while (p < test); 973 974 L120: 975 /* ------------------------------------------------------------------- 976 Initialize the backward recursion and the normalization sum. 977 ------------------------------------------------------------------- */ 978 ++n; 979 en += 2.; 980 bb = 0; 981 aa = 1. / p; 982 em = cast(double) n - 1.; 983 empal = em + nu; 984 emp2al = em - 1. + twonu; 985 sum = aa * empal * emp2al / em; 986 nend = n - b.length; 987 if (nend < 0) { 988 /* ----------------------------------------------------- 989 N < NB, so store BI[N] and set higher orders to 0.. 990 ----------------------------------------------------- */ 991 b[n - 1] = aa; 992 nend = -nend; 993 b[n .. n + nend] = 0; 994 } else { 995 if (nend > 0) { 996 /* ----------------------------------------------------- 997 Recur backward via difference equation, 998 calculating (but not storing) BI[N], until N = NB. 999 --------------------------------------------------- */ 1000 1001 for (l = 1; l <= nend; ++l) { 1002 --n; 1003 en -= 2.; 1004 cc = bb; 1005 bb = aa; 1006 /* for x ~= 1500, sum would overflow to 'inf' here, 1007 * and the final b[] /= sum would give 0 wrongly; 1008 * RE-normalize (aa, sum) here -- no need to undo */ 1009 if(nend > 100 && aa > 1e200) { 1010 /* multiply b 2^-900 = 1.18e-271 */ 1011 cc = ldexp(cc, -900); 1012 bb = ldexp(bb, -900); 1013 sum = ldexp(sum,-900); 1014 } 1015 aa = en * bb / x + cc; 1016 em -= 1.; 1017 emp2al -= 1.; 1018 if (n == 1) { 1019 break; 1020 } 1021 if (n == 2) { 1022 emp2al = 1.; 1023 } 1024 empal -= 1.; 1025 sum = (sum + aa * empal) * emp2al / em; 1026 } 1027 } 1028 /* --------------------------------------------------- 1029 Store BI[NB] 1030 --------------------------------------------------- */ 1031 b[n - 1] = aa; 1032 if (b.length <= 1) { 1033 sum = sum + sum + aa; 1034 goto L230; 1035 } 1036 /* ------------------------------------------------- 1037 Calculate and Store BI[NB-1] 1038 ------------------------------------------------- */ 1039 --n; 1040 en -= 2.; 1041 b[n - 1] = en * aa / x + bb; 1042 if (n == 1) { 1043 goto L220; 1044 } 1045 em -= 1.; 1046 if (n == 2) 1047 emp2al = 1.; 1048 else 1049 emp2al -= 1.; 1050 1051 empal -= 1.; 1052 sum = (sum + b[n - 1] * empal) * emp2al / em; 1053 } 1054 nend = n - 2; 1055 if (nend > 0) { 1056 /* -------------------------------------------- 1057 Calculate via difference equation 1058 and store BI[N], until N = 2. 1059 ------------------------------------------ */ 1060 for (l = 1; l <= nend; ++l) { 1061 --n; 1062 en -= 2.; 1063 b[n - 1] = en * b[n + 0] / x + b[n + 1]; 1064 em -= 1.; 1065 if (n == 2) 1066 emp2al = 1.; 1067 else 1068 emp2al -= 1.; 1069 empal -= 1.; 1070 sum = (sum + b[n - 1] * empal) * emp2al / em; 1071 } 1072 } 1073 /* ---------------------------------------------- 1074 Calculate BI[1] 1075 -------------------------------------------- */ 1076 b[0] = 2. * empal * b[1] / x + b[2]; 1077 L220: 1078 sum = sum + sum + b[0]; 1079 1080 L230: 1081 /* --------------------------------------------------------- 1082 Normalize. Divide all BI[N] b sum. 1083 --------------------------------------------------------- */ 1084 if (nu != 0.) 1085 sum *= (gamma_cody(1. + nu) * pow(x * .5, -nu)); 1086 if (expFlag == false) 1087 sum *= exp(-(x)); 1088 aa = enmten_BESS; 1089 if (sum > 1.) 1090 aa *= sum; 1091 for (n = 1; n <= b.length; ++n) { 1092 if (b[n - 1] < aa) 1093 b[n - 1] = 0; 1094 else 1095 b[n - 1] /= sum; 1096 } 1097 return; 1098 } else { /* small x < 1e-4 */ 1099 /* ----------------------------------------------------------- 1100 Two-term ascending series for small X. 1101 -----------------------------------------------------------*/ 1102 aa = 1.; 1103 empal = 1. + nu; 1104 /* No need to check for underflow */ 1105 halfx = .5 * x; 1106 if (nu != 0.) 1107 aa = pow(halfx, nu) / gamma_cody(empal); 1108 if (expFlag) 1109 aa *= exp(-(x)); 1110 bb = halfx * halfx; 1111 b[0] = aa + aa * bb / empal; 1112 if (x != 0. && b[0] == 0.) 1113 ncalc = 0; 1114 if (b.length > 1) { 1115 if (x == 0.) { 1116 b[1..$] = 0; 1117 } else { 1118 /* ------------------------------------------------- 1119 Calculate higher-order functions. 1120 ------------------------------------------------- */ 1121 cc = halfx; 1122 tover = (enmten_BESS + enmten_BESS) / x; 1123 if (bb != 0.) 1124 tover = enmten_BESS / bb; 1125 for (n = 2; n <= b.length; ++n) { 1126 aa /= empal; 1127 empal += 1.; 1128 aa *= cc; 1129 if (aa <= tover * empal) 1130 b[n - 1] = aa = 0; 1131 else 1132 b[n - 1] = aa + aa * bb / empal; 1133 if (b[n - 1] == 0. && ncalc > n) 1134 ncalc = n - 1; 1135 } 1136 } 1137 } 1138 } 1139 } else { /* argument out of range */ 1140 ncalc = min(b.length,0) - 1; 1141 } 1142 } 1143 1144 /// 1145 double besselJ(double x, double alpha) 1146 { 1147 ptrdiff_t nb, ncalc; 1148 double na; 1149 double* b; 1150 1151 /* NaNs propagated correctly */ 1152 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 1153 return x + alpha; 1154 if (x < 0) 1155 return double.nan; 1156 na = floor(alpha); 1157 if (alpha < 0) { 1158 /* Using Aaamowitz & Stegun 9.1.2 1159 * this may not be quite optimal (CPU and accuracy wise) */ 1160 return(besselJ(x, -alpha) * cosPi(alpha) + 1161 ((alpha == na) ? 0 : 1162 besselY(x, -alpha) * sinPi(alpha))); 1163 } 1164 nb = 1 + cast(int)na; /* b.length-1 <= alpha < b.length */ 1165 alpha -= nb-1; 1166 b = cast(double*) calloc(nb, double.sizeof).enforce("besselJ allocation error"); 1167 besselJ(x, alpha, b[0..nb], ncalc); 1168 if(ncalc != nb) {/* error input */ 1169 if(ncalc < 0) 1170 throw new Exception(format("besselJ(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 1171 x, ncalc, nb, alpha)); 1172 else 1173 throw new Exception(format("besselJ(%g,nu=%g): precision lost in result\n", 1174 x, alpha+(nb-1))); 1175 } 1176 x = b[nb-1]; 1177 free(b); 1178 return x; 1179 } 1180 1181 /// 1182 unittest { 1183 assert(std.math.approxEqual(besselJ(2, 1), 0.5767248077568733872024482422691)); 1184 assert(std.math.approxEqual(besselJ(20, 1), 0.066833124175850045578992974193)); 1185 assert(std.math.approxEqual(besselJ(1, 1.2), 0.351884)); 1186 } 1187 1188 /* modified version of besselJ that accepts a work array instead of 1189 allocating one. */ 1190 double besselJ(double x, double alpha, double[] b) 1191 { 1192 ptrdiff_t nb, ncalc; 1193 double na; 1194 1195 /* NaNs propagated correctly */ 1196 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 1197 return x + alpha; 1198 if (x < 0) 1199 return double.nan; 1200 na = floor(alpha); 1201 if (alpha < 0) { 1202 /* Using Aaamowitz & Stegun 9.1.2 1203 * this may not be quite optimal (CPU and accuracy wise) */ 1204 return(besselJ(x, -alpha, b) * cosPi(alpha) + 1205 ((alpha == na) ? 0 : 1206 besselY(x, -alpha, b) * sinPi(alpha))); 1207 } 1208 nb = 1 + cast(int)na; /* b.length-1 <= alpha < b.length */ 1209 alpha -= nb-1; 1210 besselJ(x, alpha, b[0..nb], ncalc); 1211 if(ncalc != nb) {/* error input */ 1212 if(ncalc < 0) 1213 throw new Exception(format("besselJ(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 1214 x, ncalc, nb, alpha)); 1215 else 1216 throw new Exception(format("besselJ(%g,nu=%g): precision lost in result\n", 1217 x, alpha+(nb-1))); 1218 } 1219 x = b[b.length-1]; 1220 return x; 1221 } 1222 1223 void besselJ(double x, double alpha, double[] b, ref ptrdiff_t ncalc) 1224 { 1225 /* 1226 Calculates Bessel functions J_{n+alpha} (x) 1227 for non-negative argument x, and non-negative order n+alpha, n = 0,1,..,b.length-1. 1228 1229 Explanation of variables in the calling sequence. 1230 1231 X - Non-negative argument for which J's are to be calculated. 1232 ALPHA - Fractional part of order for which 1233 J's are to be calculated. 0 <= ALPHA < 1. 1234 NB - Number of functions to be calculated, NB >= 1. 1235 The first function calculated is of order ALPHA, and the 1236 last is of order (NB - 1 + ALPHA). 1237 B - Output vector of length NB. If RJBESL 1238 terminates normally (NCALC=NB), the vector B contains the 1239 functions J/ALPHA/(X) through J/NB-1+ALPHA/(X). 1240 NCALC - Output variable indicating possible errors. 1241 Before using the vector B, the user should check that 1242 NCALC=NB, i.e., all orders have been calculated to 1243 the desired accuracy. See the following 1244 1245 **************************************************************** 1246 1247 Error return codes 1248 1249 In case of an error, NCALC != NB, and not all J's are 1250 calculated to the desired accuracy. 1251 1252 NCALC < 0: An argument is out of range. For example, 1253 NBES <= 0, ALPHA < 0 or > 1, or X is too large. 1254 In this case, b[1] is set to zero, the remainder of the 1255 B-vector is not calculated, and NCALC is set to 1256 MIN(NB,0)-1 so that NCALC != NB. 1257 1258 NB > NCALC > 0: Not all requested function values could 1259 be calculated accurately. This usually occurs because NB is 1260 much larger than ABS(X). In this case, b[N] is calculated 1261 to the desired accuracy for N <= NCALC, but precision 1262 is lost for NCALC < N <= NB. If b[N] does not vanish 1263 for N > NCALC (because it is too small to be represented), 1264 and b[N]/b[NCALC] = 10^(-K), then only the first NSIG - K 1265 significant figures of b[N] can be trusted. 1266 1267 1268 Acknowledgement 1269 1270 This program is based on a program written b David J. Sookne 1271 (2) that computes values of the Bessel functions J or I of float 1272 argument and long order. Modifications include the restriction 1273 of the computation to the J Bessel function of non-negative float 1274 argument, the extension of the computation to arbtrary positive 1275 order, and the elimination of most underflow. 1276 1277 References: 1278 1279 Olver, F.W.J., and Sookne, D.J. (1972) 1280 "A Note on Backward Recurrence Algorithms"; 1281 Math. Comp. 26, 941-947. 1282 1283 Sookne, D.J. (1973) 1284 "Bessel Functions of Real Argument and Integer Order"; 1285 NBS Jour. of Res. B. 77B, 125-132. 1286 1287 Latest modification: March 19, 1990 1288 1289 Author: W. J. Cody 1290 Applied Mathematics Division 1291 Argonne National Laboratory 1292 Argonne, IL 60439 1293 ******************************************************************* 1294 */ 1295 1296 /* --------------------------------------------------------------------- 1297 Mathematical constants 1298 1299 PI2 = 2 / PI 1300 TWOPI1 = first few significant digits of 2 * PI 1301 TWOPI2 = (2*PI - TWOPI1) to working precision, i.e., 1302 TWOPI1 + TWOPI2 = 2 * PI to extra precision. 1303 --------------------------------------------------------------------- */ 1304 static immutable double pi2 = .636619772367581343075535; 1305 static immutable double twopi1 = 6.28125; 1306 static immutable double twopi2 = .001935307179586476925286767; 1307 1308 /*--------------------------------------------------------------------- 1309 * Factorial(N) 1310 *--------------------------------------------------------------------- */ 1311 static immutable double fact[25] = [ 1.,1.,2.,6.,24.,120.,720.,5040.,40320., 1312 362880.,3628800.,39916800.,479001600.,6227020800.,87178291200., 1313 1.307674368e12,2.0922789888e13,3.55687428096e14,6.402373705728e15, 1314 1.21645100408832e17,2.43290200817664e18,5.109094217170944e19, 1315 1.12400072777760768e21,2.585201673888497664e22, 1316 6.2044840173323943936e23 ]; 1317 1318 /* Local variables */ 1319 ptrdiff_t nend, intx, nbmx, i, j, k, l, m, n, nstart; 1320 1321 double nu, twonu, capp, capq, pold, vcos, test, vsin; 1322 double p, s, t, z, alpem, halfx, aa, bb, cc, psave, plast; 1323 double tover, t1, alp2em, em, en, xc, xk, xm, psavel, gnu, xin, sum; 1324 1325 1326 /* Parameter adjustment */ 1327 // --b; 1328 1329 nu = alpha; 1330 twonu = nu + nu; 1331 1332 /*------------------------------------------------------------------- 1333 Check for out of range arguments. 1334 -------------------------------------------------------------------*/ 1335 if (b.length > 0 && x >= 0. && 0. <= nu && nu < 1.) { 1336 1337 ncalc = b.length; 1338 if(x > xlrg_BESS_IJ) { 1339 throw new Exception("besselJ, Range error"); 1340 /* indeed, the limit is 0, 1341 * but the cutoff happens too early */ 1342 b[] = 0; /*was double.infinity (really nonsense) */ 1343 return; 1344 } 1345 intx = cast(int) (x); 1346 /* Initialize result array to zero. */ 1347 b[] = 0; 1348 1349 /*=================================================================== 1350 Branch into 3 cases : 1351 1) use 2-term ascending series for small X 1352 2) use asymptotic form for large X when NB is not too large 1353 3) use recursion otherwise 1354 ===================================================================*/ 1355 1356 if (x < rtnsig_BESS) { 1357 /* --------------------------------------------------------------- 1358 Two-term ascending series for small X. 1359 --------------------------------------------------------------- */ 1360 alpem = 1. + nu; 1361 1362 halfx = (x > enmten_BESS) ? .5 * x : 0; 1363 aa = (nu != 0.) ? pow(halfx, nu) / (nu * gamma_cody(nu)) : 1.; 1364 bb = (x + 1. > 1.)? -halfx * halfx : 0; 1365 b[0] = aa + aa * bb / alpem; 1366 if (x != 0. && b[0] == 0.) 1367 ncalc = 0; 1368 1369 if (b.length != 1) { 1370 if (x <= 0.) { 1371 for (n = 2; n <= b.length; ++n) 1372 b[n - 1] = 0; 1373 } 1374 else { 1375 /* ---------------------------------------------- 1376 Calculate higher order functions. 1377 ---------------------------------------------- */ 1378 if (bb == 0.) 1379 tover = (enmten_BESS + enmten_BESS) / x; 1380 else 1381 tover = enmten_BESS / bb; 1382 cc = halfx; 1383 for (n = 2; n <= b.length; ++n) { 1384 aa /= alpem; 1385 alpem += 1.; 1386 aa *= cc; 1387 if (aa <= tover * alpem) 1388 aa = 0; 1389 1390 b[n - 1] = aa + aa * bb / alpem; 1391 if (b[n - 1] == 0. && ncalc > n) 1392 ncalc = n - 1; 1393 } 1394 } 1395 } 1396 } else if (x > 25. && b.length <= intx + 1) { 1397 /* ------------------------------------------------------------ 1398 Asymptotic series for X > 25 (and not too large b.length) 1399 ------------------------------------------------------------ */ 1400 xc = sqrt(pi2 / x); 1401 xin = 1 / (64 * x * x); 1402 if (x >= 130.) m = 4; 1403 else if (x >= 35.) m = 8; 1404 else m = 11; 1405 xm = 4. * cast(double) m; 1406 /* ------------------------------------------------ 1407 Argument reduction for SIN and COS routines. 1408 ------------------------------------------------ */ 1409 t = trunc(x / (twopi1 + twopi2) + .5); 1410 z = (x - t * twopi1) - t * twopi2 - (nu + .5) / pi2; 1411 vsin = sin(z); 1412 vcos = cos(z); 1413 gnu = twonu; 1414 for (i = 1; i <= 2; ++i) { 1415 s = (xm - 1. - gnu) * (xm - 1. + gnu) * xin * .5; 1416 t = (gnu - (xm - 3.)) * (gnu + (xm - 3.)); 1417 t1= (gnu - (xm + 1.)) * (gnu + (xm + 1.)); 1418 k = m + m; 1419 capp = s * t / fact[k]; 1420 capq = s * t1/ fact[k + 1]; 1421 xk = xm; 1422 for (; k >= 4; k -= 2) {/* k + 2(j-2) == 2m */ 1423 xk -= 4.; 1424 s = (xk - 1. - gnu) * (xk - 1. + gnu); 1425 t1 = t; 1426 t = (gnu - (xk - 3.)) * (gnu + (xk - 3.)); 1427 capp = (capp + 1. / fact[k - 2]) * s * t * xin; 1428 capq = (capq + 1. / fact[k - 1]) * s * t1 * xin; 1429 1430 } 1431 capp += 1.; 1432 capq = (capq + 1.) * (gnu * gnu - 1.) * (.125 / x); 1433 b[i - 1] = xc * (capp * vcos - capq * vsin); 1434 if (b.length == 1) 1435 return; 1436 1437 /* vsin <--> vcos */ t = vsin; vsin = -vcos; vcos = t; 1438 gnu += 2.; 1439 } 1440 /* ----------------------------------------------- 1441 If NB > 2, compute J(X,ORDER+I) for I = 2, NB-1 1442 ----------------------------------------------- */ 1443 if (b.length > 2) 1444 for (gnu = twonu + 2., j = 2; j <= b.length; j++, gnu += 2.) 1445 b[j] = gnu * b[j - 1] / x - b[j - 2]; 1446 } 1447 else { 1448 /* rtnsig_BESS <= x && ( x <= 25 || intx+1 < b.length ) : 1449 -------------------------------------------------------- 1450 Use recurrence to generate results. 1451 First initialize the calculation of P*S. 1452 -------------------------------------------------------- */ 1453 nbmx = b.length - intx; 1454 n = intx + 1; 1455 en = cast(double)(n + n) + twonu; 1456 plast = 1.; 1457 p = en / x; 1458 /* --------------------------------------------------- 1459 Calculate general significance test. 1460 --------------------------------------------------- */ 1461 test = ensig_BESS + ensig_BESS; 1462 if (nbmx >= 3) { 1463 /* ------------------------------------------------------------ 1464 Calculate P*S until N = NB-1. Check for possible overflow. 1465 ---------------------------------------------------------- */ 1466 tover = enten_BESS / ensig_BESS; 1467 nstart = intx + 2; 1468 nend = b.length - 1; 1469 en = cast(double) (nstart + nstart) - 2. + twonu; 1470 for (k = nstart; k <= nend; ++k) { 1471 n = k; 1472 en += 2.; 1473 pold = plast; 1474 plast = p; 1475 p = en * plast / x - pold; 1476 if (p > tover) { 1477 /* ------------------------------------------- 1478 To avoid overflow, divide P*S b TOVER. 1479 Calculate P*S until ABS(P) > 1. 1480 -------------------------------------------*/ 1481 tover = enten_BESS; 1482 p /= tover; 1483 plast /= tover; 1484 psave = p; 1485 psavel = plast; 1486 nstart = n + 1; 1487 do { 1488 ++n; 1489 en += 2.; 1490 pold = plast; 1491 plast = p; 1492 p = en * plast / x - pold; 1493 } while (p <= 1.); 1494 1495 bb = en / x; 1496 /* ----------------------------------------------- 1497 Calculate backward test and find NCALC, 1498 the highest N such that the test is passed. 1499 ----------------------------------------------- */ 1500 test = pold * plast * (.5 - .5 / (bb * bb)); 1501 test /= ensig_BESS; 1502 p = plast * tover; 1503 --n; 1504 en -= 2.; 1505 nend = min(b.length,n); 1506 for (l = nstart; l <= nend; ++l) { 1507 pold = psavel; 1508 psavel = psave; 1509 psave = en * psavel / x - pold; 1510 if (psave * psavel > test) { 1511 ncalc = l - 1; 1512 goto L190; 1513 } 1514 } 1515 ncalc = nend; 1516 goto L190; 1517 } 1518 } 1519 n = nend; 1520 en = cast(double) (n + n) + twonu; 1521 /* ----------------------------------------------------- 1522 Calculate special significance test for NBMX > 2. 1523 -----------------------------------------------------*/ 1524 test = max(test, sqrt(plast * ensig_BESS) * sqrt(p + p)); 1525 } 1526 /* ------------------------------------------------ 1527 Calculate P*S until significance test passes. */ 1528 do { 1529 ++n; 1530 en += 2.; 1531 pold = plast; 1532 plast = p; 1533 p = en * plast / x - pold; 1534 } while (p < test); 1535 1536 L190: 1537 /*--------------------------------------------------------------- 1538 Initialize the backward recursion and the normalization sum. 1539 --------------------------------------------------------------- */ 1540 ++n; 1541 en += 2.; 1542 bb = 0; 1543 aa = 1. / p; 1544 m = n / 2; 1545 em = cast(double)m; 1546 m = (n << 1) - (m << 2);/* = 2 n - 4 (n/2) 1547 = 0 for even, 2 for odd n */ 1548 if (m == 0) 1549 sum = 0; 1550 else { 1551 alpem = em - 1. + nu; 1552 alp2em = em + em + nu; 1553 sum = aa * alpem * alp2em / em; 1554 } 1555 nend = n - b.length; 1556 /* if (nend > 0) */ 1557 /* -------------------------------------------------------- 1558 Recur backward via difference equation, calculating 1559 (but not storing) b[N], until N = NB. 1560 -------------------------------------------------------- */ 1561 for (l = 1; l <= nend; ++l) { 1562 --n; 1563 en -= 2.; 1564 cc = bb; 1565 bb = aa; 1566 aa = en * bb / x - cc; 1567 m = m ? 0 : 2; /* m = 2 - m failed on gcc4-20041019 */ 1568 if (m != 0) { 1569 em -= 1.; 1570 alp2em = em + em + nu; 1571 if (n == 1) 1572 break; 1573 1574 alpem = em - 1. + nu; 1575 if (alpem == 0.) 1576 alpem = 1.; 1577 sum = (sum + aa * alp2em) * alpem / em; 1578 } 1579 } 1580 /*-------------------------------------------------- 1581 Store b[NB]. 1582 --------------------------------------------------*/ 1583 b[n - 1] = aa; 1584 if (nend >= 0) { 1585 if (b.length <= 1) { 1586 if (nu + 1. == 1.) 1587 alp2em = 1.; 1588 else 1589 alp2em = nu; 1590 sum += b[0] * alp2em; 1591 goto L250; 1592 } 1593 else {/*-- b.length >= 2 : --------------------------- 1594 Calculate and store b[NB-1]. 1595 ----------------------------------------*/ 1596 --n; 1597 en -= 2.; 1598 b[n - 1] = en * aa / x - bb; 1599 if (n == 1) 1600 goto L240; 1601 1602 m = m ? 0 : 2; /* m = 2 - m failed on gcc4-20041019 */ 1603 if (m != 0) { 1604 em -= 1.; 1605 alp2em = em + em + nu; 1606 alpem = em - 1. + nu; 1607 if (alpem == 0.) 1608 alpem = 1.; 1609 sum = (sum + b[n - 1] * alp2em) * alpem / em; 1610 } 1611 } 1612 } 1613 1614 /* if (n - 2 != 0) */ 1615 /* -------------------------------------------------------- 1616 Calculate via difference equation and store b[N], 1617 until N = 2. 1618 -------------------------------------------------------- */ 1619 for (n = n-1; n >= 2; n--) { 1620 en -= 2.; 1621 b[n - 1] = en * b[n + 0] / x - b[n + 1]; 1622 m = m ? 0 : 2; /* m = 2 - m failed on gcc4-20041019 */ 1623 if (m != 0) { 1624 em -= 1.; 1625 alp2em = em + em + nu; 1626 alpem = em - 1. + nu; 1627 if (alpem == 0.) 1628 alpem = 1.; 1629 sum = (sum + b[n - 1] * alp2em) * alpem / em; 1630 } 1631 } 1632 /* --------------------------------------- 1633 Calculate b[1]. 1634 -----------------------------------------*/ 1635 b[0] = 2. * (nu + 1.) * b[1] / x - b[2]; 1636 1637 L240: 1638 em -= 1.; 1639 alp2em = em + em + nu; 1640 if (alp2em == 0.) 1641 alp2em = 1.; 1642 sum += b[0] * alp2em; 1643 1644 L250: 1645 /* --------------------------------------------------- 1646 Normalize. Divide all b[N] b sum. 1647 ---------------------------------------------------*/ 1648 /* if (nu + 1. != 1.) poor test */ 1649 if(fabs(nu) > 1e-15) 1650 sum *= (gamma_cody(nu) * pow(.5* x, -nu)); 1651 1652 aa = enmten_BESS; 1653 if (sum > 1.) 1654 aa *= sum; 1655 for (n = 1; n <= b.length; ++n) { 1656 if (fabs(b[n - 1]) < aa) 1657 b[n - 1] = 0; 1658 else 1659 b[n - 1] /= sum; 1660 } 1661 } 1662 1663 } 1664 else { 1665 /* Error return -- X, NB, or ALPHA is out of range : */ 1666 b[0] = 0; 1667 ncalc = min(b.length, 0) - 1; 1668 } 1669 } 1670 1671 /// 1672 double besselY(double x, double alpha) 1673 { 1674 ptrdiff_t nb, ncalc; 1675 double na; 1676 double* b; 1677 1678 /* NaNs propagated correctly */ 1679 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 1680 return x + alpha; 1681 if (x < 0) 1682 return double.nan; 1683 na = floor(alpha); 1684 if (alpha < 0) { 1685 /* Using Aaamowitz & Stegun 9.1.2 1686 * this may not be quite optimal (CPU and accuracy wise) */ 1687 return(besselY(x, -alpha) * cosPi(alpha) - 1688 ((alpha == na) ? 0 : 1689 besselJ(x, -alpha) * sinPi(alpha))); 1690 } 1691 nb = 1+ cast(int)na;/* b.length-1 <= alpha < b.length */ 1692 alpha -= nb-1; 1693 b = cast(double*) calloc(nb, double.sizeof).enforce("besselY allocation error");;; 1694 besselY(x, alpha, b[0..nb], ncalc); 1695 if(ncalc != nb) {/* error input */ 1696 if(ncalc == -1) { 1697 free(b); 1698 return double.infinity; 1699 } 1700 else if(ncalc < -1) 1701 throw new Exception(format("besselY(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 1702 x, ncalc, nb, alpha)); 1703 else /* ncalc >= 0 */ 1704 throw new Exception(format("besselY(%g,nu=%g): precision lost in result\n", 1705 x, alpha+(nb-1))); 1706 } 1707 x = b[nb-1]; 1708 free(b); 1709 return x; 1710 } 1711 1712 1713 /// 1714 unittest { 1715 assert(std.math.approxEqual(besselY(2, 1), -0.1070324315409375468883707722774)); 1716 assert(std.math.approxEqual(besselY(20, 1), -0.165511614362521295863976023243)); 1717 assert(std.math.approxEqual(besselY(1, 1.2), -0.901215)); 1718 } 1719 1720 /* modified version of besselY that accepts a work array instead of 1721 allocating one. */ 1722 double besselY(double x, double alpha, double[] b) 1723 { 1724 ptrdiff_t nb, ncalc; 1725 double na; 1726 1727 /* NaNs propagated correctly */ 1728 if (std.math.isNaN(x) || std.math.isNaN(alpha)) 1729 return x + alpha; 1730 if (x < 0) 1731 return double.nan; 1732 na = floor(alpha); 1733 if (alpha < 0) { 1734 /* Using Aaamowitz & Stegun 9.1.2 1735 * this may not be quite optimal (CPU and accuracy wise) */ 1736 return(besselY(x, -alpha, b) * cosPi(alpha) - 1737 ((alpha == na) ? 0 : 1738 besselJ(x, -alpha, b) * sinPi(alpha))); 1739 } 1740 nb = 1+ cast(int)na;/* b.length-1 <= alpha < b.length */ 1741 alpha -= nb-1; 1742 besselY(x, alpha, b[0..nb], ncalc); 1743 if(ncalc != nb) {/* error input */ 1744 if(ncalc == -1) 1745 return double.infinity; 1746 else if(ncalc < -1) 1747 throw new Exception(format("besselY(%g): ncalc (=%ld) != b.length (=%ld); alpha=%g. Arg. out of range?\n", 1748 x, ncalc, nb, alpha)); 1749 else /* ncalc >= 0 */ 1750 throw new Exception(format("besselY(%g,nu=%g): precision lost in result\n", 1751 x, alpha+(nb-1))); 1752 } 1753 x = b[nb-1]; 1754 return x; 1755 } 1756 1757 1758 void besselY(double x, double alpha, double[] b, ref ptrdiff_t ncalc) 1759 { 1760 /* ---------------------------------------------------------------------- 1761 1762 This routine calculates Bessel functions Y_(N+ALPHA) (X) 1763 v for non-negative argument X, and non-negative order N+ALPHA. 1764 1765 1766 Explanation of variables in the calling sequence 1767 1768 X - Non-negative argument for which 1769 Y's are to be calculated. 1770 ALPHA - Fractional part of order for which 1771 Y's are to be calculated. 0 <= ALPHA < 1.0. 1772 NB - Number of functions to be calculated, NB > 0. 1773 The first function calculated is of order ALPHA, and the 1774 last is of order (NB - 1 + ALPHA). 1775 BY - Output vector of length NB. If the 1776 routine terminates normally (NCALC=NB), the vector BY 1777 contains the functions Y(ALPHA,X), ... , Y(NB-1+ALPHA,X), 1778 If (0 < NCALC < NB), BY(I) contains correct function 1779 values for I <= NCALC, and contains the ratios 1780 Y(ALPHA+I-1,X)/Y(ALPHA+I-2,X) for the rest of the array. 1781 NCALC - Output variable indicating possible errors. 1782 Before using the vector BY, the user should check that 1783 NCALC=NB, i.e., all orders have been calculated to 1784 the desired accuracy. See error returns below. 1785 1786 1787 ******************************************************************* 1788 1789 Error returns 1790 1791 In case of an error, NCALC != NB, and not all Y's are 1792 calculated to the desired accuracy. 1793 1794 NCALC < -1: An argument is out of range. For example, 1795 NB <= 0, IZE is not 1 or 2, or IZE=1 and ABS(X) >= 1796 XMAX. In this case, BY[0] = 0.0, the remainder of the 1797 BY-vector is not calculated, and NCALC is set to 1798 MIN0(NB,0)-2 so that NCALC != NB. 1799 NCALC = -1: Y(ALPHA,X) >= XINF. The requested function 1800 values are set to 0.0. 1801 1 < NCALC < NB: Not all requested function values could 1802 be calculated accurately. BY(I) contains correct function 1803 values for I <= NCALC, and and the remaining NB-NCALC 1804 array elements contain 0.0. 1805 1806 1807 Intrinsic functions required are: 1808 1809 DBLE, EXP, INT, MAX, MIN, REAL, SQRT 1810 1811 1812 Acknowledgement 1813 1814 This program draws heavily on Temme's Algol program for Y(a,x) 1815 and Y(a+1,x) and on Campbell's programs for Y_nu(x). Temme's 1816 scheme is used for x < THRESH, and Campbell's scheme is used 1817 in the asymptotic region. Segments of code from both sources 1818 have been translated into Fortran 77, merged, and heavily modified. 1819 Modifications include parameterization of machine dependencies, 1820 use of a new approximation for ln(gamma(x)), and built-in 1821 protection against over/underflow. 1822 1823 References: "Bessel functions J_nu(x) and Y_nu(x) of float 1824 order and float argument," Campbell, J. B., 1825 Comp. Phy. Comm. 18, 1979, pp. 133-142. 1826 1827 "On the numerical evaluation of the ordinary 1828 Bessel function of the second kind," Temme, 1829 N. M., J. Comput. Phys. 21, 1976, pp. 343-350. 1830 1831 Latest modification: March 19, 1990 1832 1833 Modified b: W. J. Cody 1834 Applied Mathematics Division 1835 Argonne National Laboratory 1836 Argonne, IL 60439 1837 ----------------------------------------------------------------------*/ 1838 1839 1840 /* ---------------------------------------------------------------------- 1841 Mathematical constants 1842 FIVPI = 5*PI 1843 PIM5 = 5*PI - 15 1844 ----------------------------------------------------------------------*/ 1845 static immutable double fivpi = 15.707963267948966192; 1846 static immutable double pim5 = .70796326794896619231; 1847 1848 /*---------------------------------------------------------------------- 1849 Coefficients for Chebshev polynomial expansion of 1850 1/gamma(1-x), abs(x) <= .5 1851 ----------------------------------------------------------------------*/ 1852 static immutable double ch[21] = [ -6.7735241822398840964e-24, 1853 -6.1455180116049879894e-23,2.9017595056104745456e-21, 1854 1.3639417919073099464e-19,2.3826220476859635824e-18, 1855 -9.0642907957550702534e-18,-1.4943667065169001769e-15, 1856 -3.3919078305362211264e-14,-1.7023776642512729175e-13, 1857 9.1609750938768647911e-12,2.4230957900482704055e-10, 1858 1.7451364971382984243e-9,-3.3126119768180852711e-8, 1859 -8.6592079961391259661e-7,-4.9717367041957398581e-6, 1860 7.6309597585908126618e-5,.0012719271366545622927, 1861 .0017063050710955562222,-.07685284084478667369, 1862 -.28387654227602353814,.92187029365045265648 ]; 1863 1864 /* Local variables */ 1865 ptrdiff_t i, k, na; 1866 1867 double alfa, div, ddiv, even, gamma, term, cosmu, sinmu, 1868 a, c, d, e, f, g, h, p, q, r, s, d1, d2, q0, pa,pa1, qa,qa1, 1869 en, en1, nu, ex, ya,ya1, twobx, den, odd, aye, dmu, x2, xna; 1870 1871 en1 = ya = ya1 = 0; /* -Wall */ 1872 1873 ex = x; 1874 nu = alpha; 1875 if (b.length > 0 && 0. <= nu && nu < 1.) { 1876 if(ex < double.min_normal || ex > xlrg_BESS_Y) { 1877 /* Warning is not really appropriate, give 1878 * proper limit: 1879 * ML_ERROR(ME_RANGE, "besselY"); */ 1880 ncalc = b.length; 1881 if(ex > xlrg_BESS_Y) b[0]= 0; /*was double.infinity */ 1882 else if(ex < double.min_normal) b[0]=-double.infinity; 1883 for(i=0; i < b.length; i++) 1884 b[i] = b[0]; 1885 return; 1886 } 1887 xna = trunc(nu + .5); 1888 na = cast(int) xna; 1889 if (na == 1) {/* <==> .5 <= alpha < 1 <==> -5. <= nu < 0 */ 1890 nu -= xna; 1891 } 1892 if (nu == -.5) { 1893 p = M_SQRT_2dPI / sqrt(ex); 1894 ya = p * sin(ex); 1895 ya1 = -p * cos(ex); 1896 } else if (ex < 3.) { 1897 /* ------------------------------------------------------------- 1898 Use Temme's scheme for small X 1899 ------------------------------------------------------------- */ 1900 a = ex * .5; 1901 d = -log(a); 1902 f = nu * d; 1903 e = pow(a, -nu); 1904 if (fabs(nu) < M_eps_sinc) 1905 c = std.math.M_1_PI; 1906 else 1907 c = nu / sinPi(nu); 1908 1909 /* ------------------------------------------------------------ 1910 Computation of sinh(f)/f 1911 ------------------------------------------------------------ */ 1912 if (fabs(f) < 1.) { 1913 x2 = f * f; 1914 en = 19.; 1915 s = 1.; 1916 for (i = 1; i <= 9; ++i) { 1917 s = s * x2 / en / (en - 1.) + 1.; 1918 en -= 2.; 1919 } 1920 } else { 1921 s = (e - 1. / e) * .5 / f; 1922 } 1923 /* -------------------------------------------------------- 1924 Computation of 1/gamma(1-a) using Chebshev polynomials */ 1925 x2 = nu * nu * 8.; 1926 aye = ch[0]; 1927 even = 0; 1928 alfa = ch[1]; 1929 odd = 0; 1930 for (i = 3; i <= 19; i += 2) { 1931 even = -(aye + aye + even); 1932 aye = -even * x2 - aye + ch[i - 1]; 1933 odd = -(alfa + alfa + odd); 1934 alfa = -odd * x2 - alfa + ch[i]; 1935 } 1936 even = (even * .5 + aye) * x2 - aye + ch[20]; 1937 odd = (odd + alfa) * 2.; 1938 gamma = odd * nu + even; 1939 /* End of computation of 1/gamma(1-a) 1940 ----------------------------------------------------------- */ 1941 g = e * gamma; 1942 e = (e + 1. / e) * .5; 1943 f = 2. * c * (odd * e + even * s * d); 1944 e = nu * nu; 1945 p = g * c; 1946 q = std.math.M_1_PI / g; 1947 c = nu * std.math.PI_2; 1948 if (fabs(c) < M_eps_sinc) 1949 r = 1.; 1950 else 1951 r = sinPi(nu/2) / c; 1952 1953 r = cast(double)std.math.PI * c * r * r; 1954 c = 1.; 1955 d = -(a * a); 1956 h = 0; 1957 ya = f + r * q; 1958 ya1 = p; 1959 en = 1.; 1960 1961 while (fabs(g / (1. + fabs(ya))) + 1962 fabs(h / (1. + fabs(ya1))) > double.epsilon) { 1963 f = (f * en + p + q) / (en * en - e); 1964 c *= (d / en); 1965 p /= en - nu; 1966 q /= en + nu; 1967 g = c * (f + r * q); 1968 h = c * p - en * g; 1969 ya += g; 1970 ya1+= h; 1971 en += 1.; 1972 } 1973 ya = -ya; 1974 ya1 = -ya1 / a; 1975 } else if (ex < thresh_BESS_Y) { 1976 /* -------------------------------------------------------------- 1977 Use Temme's scheme for moderate X : 3 <= x < 16 1978 -------------------------------------------------------------- */ 1979 c = (.5 - nu) * (.5 + nu); 1980 a = ex + ex; 1981 e = ex * std.math.M_1_PI * cosPi(nu) / double.epsilon; 1982 e *= e; 1983 p = 1.; 1984 q = -ex; 1985 r = 1. + ex * ex; 1986 s = r; 1987 en = 2.; 1988 while (r * en * en < e) { 1989 en1 = en + 1.; 1990 d = (en - 1. + c / en) / s; 1991 p = (en + en - p * d) / en1; 1992 q = (-a + q * d) / en1; 1993 s = p * p + q * q; 1994 r *= s; 1995 en = en1; 1996 } 1997 f = p / s; 1998 p = f; 1999 g = -q / s; 2000 q = g; 2001 L220: 2002 en -= 1.; 2003 if (en > 0.) { 2004 r = en1 * (2. - p) - 2.; 2005 s = a + en1 * q; 2006 d = (en - 1. + c / en) / (r * r + s * s); 2007 p = d * r; 2008 q = d * s; 2009 e = f + 1.; 2010 f = p * e - g * q; 2011 g = q * e + p * g; 2012 en1 = en; 2013 goto L220; 2014 } 2015 f = 1. + f; 2016 d = f * f + g * g; 2017 pa = f / d; 2018 qa = -g / d; 2019 d = nu + .5 - p; 2020 q += ex; 2021 pa1 = (pa * q - qa * d) / ex; 2022 qa1 = (qa * q + pa * d) / ex; 2023 a = ex - std.math.PI_2 * (nu + .5); 2024 c = cos(a); 2025 s = sin(a); 2026 d = M_SQRT_2dPI / sqrt(ex); 2027 ya = d * (pa * s + qa * c); 2028 ya1 = d * (qa1 * s - pa1 * c); 2029 } else { /* x > thresh_BESS_Y */ 2030 /* ---------------------------------------------------------- 2031 Use Campbell's asymptotic scheme. 2032 ---------------------------------------------------------- */ 2033 na = 0; 2034 d1 = trunc(ex / fivpi); 2035 i = cast(int) d1; 2036 dmu = ex - 15. * d1 - d1 * pim5 - (alpha + .5) * std.math.PI_2; 2037 if (i - (i / 2 << 1) == 0) { 2038 cosmu = cos(dmu); 2039 sinmu = sin(dmu); 2040 } else { 2041 cosmu = -cos(dmu); 2042 sinmu = -sin(dmu); 2043 } 2044 ddiv = 8. * ex; 2045 dmu = alpha; 2046 den = sqrt(ex); 2047 for (k = 1; k <= 2; ++k) { 2048 p = cosmu; 2049 cosmu = sinmu; 2050 sinmu = -p; 2051 d1 = (2. * dmu - 1.) * (2. * dmu + 1.); 2052 d2 = 0; 2053 div = ddiv; 2054 p = 0; 2055 q = 0; 2056 q0 = d1 / div; 2057 term = q0; 2058 for (i = 2; i <= 20; ++i) { 2059 d2 += 8.; 2060 d1 -= d2; 2061 div += ddiv; 2062 term = -term * d1 / div; 2063 p += term; 2064 d2 += 8.; 2065 d1 -= d2; 2066 div += ddiv; 2067 term *= (d1 / div); 2068 q += term; 2069 if (fabs(term) <= double.epsilon) { 2070 break; 2071 } 2072 } 2073 p += 1.; 2074 q += q0; 2075 if (k == 1) 2076 ya = M_SQRT_2dPI * (p * cosmu - q * sinmu) / den; 2077 else 2078 ya1 = M_SQRT_2dPI * (p * cosmu - q * sinmu) / den; 2079 dmu += 1.; 2080 } 2081 } 2082 if (na == 1) { 2083 h = 2. * (nu + 1.) / ex; 2084 if (h > 1.) { 2085 if (fabs(ya1) > double.max / h) { 2086 h = 0; 2087 ya = 0; 2088 } 2089 } 2090 h = h * ya1 - ya; 2091 ya = ya1; 2092 ya1 = h; 2093 } 2094 2095 /* --------------------------------------------------------------- 2096 Now have first one or two Y's 2097 --------------------------------------------------------------- */ 2098 b[0] = ya; 2099 ncalc = 1; 2100 if(b.length > 1) { 2101 b[1] = ya1; 2102 if (ya1 != 0.) { 2103 aye = 1. + alpha; 2104 twobx = 2. / ex; 2105 ncalc = 2; 2106 for (i = 2; i < b.length; ++i) { 2107 if (twobx < 1.) { 2108 if (fabs(b[i - 1]) * twobx >= double.max / aye) 2109 goto L450; 2110 } else { 2111 if (fabs(b[i - 1]) >= double.max / aye / twobx) 2112 goto L450; 2113 } 2114 b[i] = twobx * aye * b[i - 1] - b[i - 2]; 2115 aye += 1.; 2116 ncalc++; 2117 } 2118 } 2119 } 2120 L450: 2121 for (i = ncalc; i < b.length; ++i) 2122 b[i] = -double.infinity;/* was 0 */ 2123 2124 } else { 2125 b[0] = 0; 2126 ncalc = min(b.length,0) - 1; 2127 } 2128 } 2129 2130 2131 private: 2132 2133 double gamma_cody(double x) 2134 { 2135 /* ---------------------------------------------------------------------- 2136 2137 This routine calculates the GAMMA function for a float argument X. 2138 Computation is based on an algorithm outlined in reference [1]. 2139 The program uses rational functions that approximate the GAMMA 2140 function to at least 20 significant decimal digits. Coefficients 2141 for the approximation over the interval (1,2) are unpublished. 2142 Those for the approximation for X >= 12 are from reference [2]. 2143 The accuracy achieved depends on the arithmetic system, the 2144 compiler, the intrinsic functions, and proper selection of the 2145 machine-dependent constants. 2146 2147 ******************************************************************* 2148 2149 Error returns 2150 2151 The program returns the value XINF for singularities or 2152 when overflow would occur. The computation is believed 2153 to be free of underflow and overflow. 2154 2155 Intrinsic functions required are: 2156 2157 INT, DBLE, EXP, LOG, REAL, SIN 2158 2159 2160 References: 2161 [1] "An Overview of Software Development for Special Functions", 2162 W. J. Cody, Lecture Notes in Mathematics, 506, 2163 Numerical Analysis Dundee, 1975, G. A. Watson (ed.), 2164 Springer Verlag, Berlin, 1976. 2165 2166 [2] Computer Approximations, Hart, Et. Al., Wiley and sons, New York, 1968. 2167 2168 Latest modification: October 12, 1989 2169 2170 Authors: W. J. Cody and L. Stoltz 2171 Applied Mathematics Division 2172 Argonne National Laboratory 2173 Argonne, IL 60439 2174 ----------------------------------------------------------------------*/ 2175 2176 /* ---------------------------------------------------------------------- 2177 Mathematical constants 2178 ----------------------------------------------------------------------*/ 2179 enum double sqrtpi = .9189385332046727417803297; /* == ??? */ 2180 2181 /* ******************************************************************* 2182 2183 Explanation of machine-dependent constants 2184 2185 beta - radix for the floating-point representation 2186 maxexp - the smallest positive power of beta that overflows 2187 XBIG - the largest argument for which GAMMA(X) is representable 2188 in the machine, i.e., the solution to the equation 2189 GAMMA(XBIG) = beta**maxexp 2190 XINF - the largest machine representable floating-point number; 2191 approximately beta**maxexp 2192 EPS - the smallest positive floating-point number such that 1.0+EPS > 1.0 2193 XMININ - the smallest positive floating-point number such that 2194 1/XMININ is machine representable 2195 2196 Approximate values for some important machines are: 2197 2198 beta maxexp XBIG 2199 2200 CRAY-1 (S.P.) 2 8191 966.961 2201 Cyber 180/855 2202 under NOS (S.P.) 2 1070 177.803 2203 IEEE (IBM/XT, 2204 SUN, etc.) (S.P.) 2 128 35.040 2205 IEEE (IBM/XT, 2206 SUN, etc.) (D.P.) 2 1024 171.624 2207 IBM 3033 (D.P.) 16 63 57.574 2208 VAX D-Format (D.P.) 2 127 34.844 2209 VAX G-Format (D.P.) 2 1023 171.489 2210 2211 XINF EPS XMININ 2212 2213 CRAY-1 (S.P.) 5.45E+2465 7.11E-15 1.84E-2466 2214 Cyber 180/855 2215 under NOS (S.P.) 1.26E+322 3.55E-15 3.14E-294 2216 IEEE (IBM/XT, 2217 SUN, etc.) (S.P.) 3.40E+38 1.19E-7 1.18E-38 2218 IEEE (IBM/XT, 2219 SUN, etc.) (D.P.) 1.79D+308 2.22D-16 2.23D-308 2220 IBM 3033 (D.P.) 7.23D+75 2.22D-16 1.39D-76 2221 VAX D-Format (D.P.) 1.70D+38 1.39D-17 5.88D-39 2222 VAX G-Format (D.P.) 8.98D+307 1.11D-16 1.12D-308 2223 2224 ******************************************************************* 2225 2226 ---------------------------------------------------------------------- 2227 Machine dependent parameters 2228 ---------------------------------------------------------------------- 2229 */ 2230 2231 2232 enum double xbg = 171.624; 2233 /* ML_POSINF == const double xinf = 1.79e308;*/ 2234 /* DBL_EPSILON = const double eps = 2.22e-16;*/ 2235 /* DBL_MIN == const double xminin = 2.23e-308;*/ 2236 2237 /*---------------------------------------------------------------------- 2238 Numerator and denominator coefficients for rational minimax 2239 approximation over (1,2). 2240 ----------------------------------------------------------------------*/ 2241 static immutable double[8] p = [ 2242 -1.71618513886549492533811, 2243 24.7656508055759199108314,-379.804256470945635097577, 2244 629.331155312818442661052,866.966202790413211295064, 2245 -31451.2729688483675254357,-36144.4134186911729807069, 2246 66456.1438202405440627855 ]; 2247 static immutable double[8] q = [ 2248 -30.8402300119738975254353, 2249 315.350626979604161529144,-1015.15636749021914166146, 2250 -3107.77167157231109440444,22538.1184209801510330112, 2251 4755.84627752788110767815,-134659.959864969306392456, 2252 -115132.259675553483497211 ]; 2253 /*---------------------------------------------------------------------- 2254 Coefficients for minimax approximation over (12, INF). 2255 ----------------------------------------------------------------------*/ 2256 static immutable double[7] c = [ 2257 -.001910444077728,8.4171387781295e-4, 2258 -5.952379913043012e-4,7.93650793500350248e-4, 2259 -.002777777777777681622553,.08333333333333333331554247, 2260 .0057083835261 ]; 2261 2262 /* Local variables */ 2263 int i, n; 2264 int parity;/*logical*/ 2265 double fact, xden, xnum, y, z, yi, res, sum, ysq; 2266 2267 parity = (0); 2268 fact = 1.; 2269 n = 0; 2270 y = x; 2271 if (y <= 0.) { 2272 /* ------------------------------------------------------------- 2273 Argument is negative 2274 ------------------------------------------------------------- */ 2275 y = -x; 2276 yi = trunc(y); 2277 res = y - yi; 2278 if (res != 0.) { 2279 if (yi != trunc(yi * .5) * 2.) 2280 parity = (1); 2281 fact = -std.math.PI / sinPi(res); 2282 y += 1.; 2283 } else { 2284 return(double.infinity); 2285 } 2286 } 2287 /* ----------------------------------------------------------------- 2288 Argument is positive 2289 -----------------------------------------------------------------*/ 2290 if (y < double.epsilon) { 2291 /* -------------------------------------------------------------- 2292 Argument < EPS 2293 -------------------------------------------------------------- */ 2294 if (y >= double.min_normal) { 2295 res = 1. / y; 2296 } else { 2297 return(double.infinity); 2298 } 2299 } else if (y < 12.) { 2300 yi = y; 2301 if (y < 1.) { 2302 /* --------------------------------------------------------- 2303 EPS < argument < 1 2304 --------------------------------------------------------- */ 2305 z = y; 2306 y += 1.; 2307 } else { 2308 /* ----------------------------------------------------------- 2309 1 <= argument < 12, reduce argument if necessary 2310 ----------------------------------------------------------- */ 2311 n = cast(int) y - 1; 2312 y -= cast(double) n; 2313 z = y - 1.; 2314 } 2315 /* --------------------------------------------------------- 2316 Evaluate approximation for 1. < argument < 2. 2317 ---------------------------------------------------------*/ 2318 xnum = 0; 2319 xden = 1.; 2320 for (i = 0; i < 8; ++i) { 2321 xnum = (xnum + p[i]) * z; 2322 xden = xden * z + q[i]; 2323 } 2324 res = xnum / xden + 1.; 2325 if (yi < y) { 2326 /* -------------------------------------------------------- 2327 Adjust result for case 0. < argument < 1. 2328 -------------------------------------------------------- */ 2329 res /= yi; 2330 } else if (yi > y) { 2331 /* ---------------------------------------------------------- 2332 Adjust result for case 2. < argument < 12. 2333 ---------------------------------------------------------- */ 2334 for (i = 0; i < n; ++i) { 2335 res *= y; 2336 y += 1.; 2337 } 2338 } 2339 } else { 2340 /* ------------------------------------------------------------- 2341 Evaluate for argument >= 12., 2342 ------------------------------------------------------------- */ 2343 if (y <= xbg) { 2344 ysq = y * y; 2345 sum = c[6]; 2346 for (i = 0; i < 6; ++i) { 2347 sum = sum / ysq + c[i]; 2348 } 2349 sum = sum / y - y + sqrtpi; 2350 sum += (y - .5) * log(y); 2351 res = exp(sum); 2352 } else { 2353 return double.infinity; 2354 } 2355 } 2356 /* ---------------------------------------------------------------------- 2357 Final adjustments and return 2358 ----------------------------------------------------------------------*/ 2359 if (parity) 2360 res = -res; 2361 if (fact != 1.) 2362 res = fact / res; 2363 return res; 2364 } 2365 2366 /// sin of pix: 2367 T sinPi(T)(T x) 2368 if(isFloatingPoint!T) 2369 { 2370 if(x < 0) 2371 return -sinPi(-x); 2372 // sin of pix: 2373 bool invert; 2374 if(x < cast(T)0.5) 2375 return sin(T(std.math.PI) * x); 2376 if(x < 1) 2377 { 2378 invert = true; 2379 x = -x; 2380 } 2381 else 2382 invert = false; 2383 2384 T rem = floor(x); 2385 if(cast(int)rem & 1) 2386 invert = !invert; 2387 rem = x - rem; 2388 if(rem > cast(T)0.5) 2389 rem = 1 - rem; 2390 if(rem == cast(T)0.5) 2391 return invert ? -1 : 1; 2392 2393 rem = sin(T(std.math.PI) * rem); 2394 return invert ? T(-rem) : rem; 2395 } 2396 2397 unittest 2398 { 2399 import std.math : approxEqual; 2400 assert(sinPi(0.0) == 0); 2401 assert(sinPi(1.0) == 0); 2402 assert(sinPi(+1.0/6).approxEqual(+0.5)); 2403 assert(sinPi(-1.0/6).approxEqual(-0.5)); 2404 assert(sinPi(+5.0/6).approxEqual(+0.5)); 2405 assert(sinPi(-5.0/6).approxEqual(-0.5)); 2406 assert(sinPi(+2.0) == 0); 2407 assert(sinPi(-2.0) == 0); 2408 assert(sinPi(+0.5) == +1); 2409 assert(sinPi(-0.5) == -1); 2410 } 2411 2412 2413 /// cos of pix: 2414 T cosPi(T)(T x) 2415 if(isFloatingPoint!T) 2416 { 2417 // cos of pix: 2418 bool invert = false; 2419 if(fabs(x) < 0.5) 2420 return cos(T(std.math.PI) * x); 2421 2422 if(x < cast(T)1) 2423 { 2424 x = -x; 2425 } 2426 T rem = floor(x); 2427 if(cast(int)rem & 1) 2428 invert = !invert; 2429 rem = x - rem; 2430 if(rem > cast(T)0.5) 2431 { 2432 rem = 1 - rem; 2433 invert = !invert; 2434 } 2435 if(rem == cast(T)0.5) 2436 return 0; 2437 2438 rem = cos(T(std.math.PI) * rem); 2439 return invert ? T(-rem) : rem; 2440 } 2441 2442 2443 unittest 2444 { 2445 import std.math : approxEqual; 2446 assert(cosPi(0.0) == 1); 2447 assert(cosPi(1.0) == -1); 2448 assert(cosPi(+1.0/3).approxEqual(+0.5)); 2449 assert(cosPi(-1.0/3).approxEqual(+0.5)); 2450 assert(cosPi(+2.0/3).approxEqual(-0.5)); 2451 assert(cosPi(-2.0/3).approxEqual(-0.5)); 2452 assert(cosPi(2.0) == 1); 2453 assert(cosPi(0.5) == 0); 2454 }