TMB Documentation  v1.9.11
bessel_y.cpp
1 /*
2  * Mathlib : A C Library of Special Functions
3  * Copyright (C) 1998-2015 Ross Ihaka and the R Core team.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, a copy is available at
17  * https://www.R-project.org/Licenses/
18  */
19 
20 /* DESCRIPTION --> see below */
21 
22 
23 /* From http://www.netlib.org/specfun/rybesl Fortran translated by f2c,...
24  * ------------------------------=#---- Martin Maechler, ETH Zurich
25  */
26 
27 #include "bessel.h"
28 
29 #ifndef MATHLIB_STANDALONE
30 #include <R_ext/Memory.h>
31 #endif
32 
33 #define min0(x, y) (((x) <= (y)) ? (x) : (y))
34 
35 template<class Float>
36 static void Y_bessel(Float *x, Float *alpha, int *nb,
37  Float *by, int *ncalc);
38 
39 // unused now from R
40 template<class Float>
41 Float bessel_y(Float x, Float alpha)
42 {
43  int nb, ncalc;
44  Float na, *by;
45 #ifndef MATHLIB_STANDALONE
46  const void *vmax;
47 #endif
48 
49 #ifdef IEEE_754
50  /* NaNs propagated correctly */
51  if (ISNAN(x) || ISNAN(alpha)) return x + alpha;
52 #endif
53  if (x < 0) {
54  ML_ERROR(ME_RANGE, "bessel_y");
55  return ML_NAN;
56  }
57  na = floor(alpha);
58  if (alpha < 0) {
59  /* Using Abramowitz & Stegun 9.1.2
60  * this may not be quite optimal (CPU and accuracy wise) */
61  return(((alpha - na == 0.5) ? 0 : bessel_y<Float>(x, -alpha) * cospi(alpha)) -
62  ((alpha == na ) ? 0 : bessel_j<Float>(x, -alpha) * sinpi(alpha)));
63  }
64  else if (alpha > 1e7) {
65  MATHLIB_WARNING(_("besselY(x, nu): nu=%g too large for bessel_y() algorithm"),
66  alpha);
67  return ML_NAN;
68  }
69  nb = 1+ (int)trunc(na);/* nb-1 <= alpha < nb */
70  alpha -= (double)(nb-1);
71 #ifdef MATHLIB_STANDALONE
72  by = (Float *) calloc(nb, sizeof(Float));
73  if (!by) MATHLIB_ERROR("%s", _("bessel_y allocation error"));
74 #else
75  vmax = vmaxget();
76  by = (Float *) R_alloc((size_t) nb, sizeof(Float));
77 #endif
78  Y_bessel(&x, &alpha, &nb, by, &ncalc);
79  if(ncalc != nb) {/* error input */
80  if(ncalc == -1) {
81 #ifdef MATHLIB_STANDALONE
82  free(by);
83 #else
84  vmaxset(vmax);
85 #endif
86  return ML_POSINF;
87  }
88  else if(ncalc < -1)
89  MATHLIB_WARNING4(_("bessel_y(%g): ncalc (=%d) != nb (=%d); alpha=%g. Arg. out of range?\n"),
90  x, ncalc, nb, alpha);
91  else /* ncalc >= 0 */
92  MATHLIB_WARNING2(_("bessel_y(%g,nu=%g): precision lost in result\n"),
93  x, alpha+(double)nb-1);
94  }
95  x = by[nb-1];
96 #ifdef MATHLIB_STANDALONE
97  free(by);
98 #else
99  vmaxset(vmax);
100 #endif
101  return x;
102 }
103 
104 /* Called from R: modified version of bessel_y(), accepting a work array
105  * instead of allocating one. */
106 template<class Float>
107 Float bessel_y_ex(Float x, Float alpha, Float *by)
108 {
109  int nb, ncalc;
110  Float na;
111 
112 #ifdef IEEE_754
113  /* NaNs propagated correctly */
114  if (ISNAN(x) || ISNAN(alpha)) return x + alpha;
115 #endif
116  if (x < 0) {
117  ML_ERROR(ME_RANGE, "bessel_y");
118  return ML_NAN;
119  }
120  na = floor(alpha);
121  if (alpha < 0) {
122  /* Using Abramowitz & Stegun 9.1.2
123  * this may not be quite optimal (CPU and accuracy wise) */
124  return(((alpha - na == 0.5) ? 0 : bessel_y_ex(x, -alpha, by) * cospi(alpha)) -
125  ((alpha == na ) ? 0 : bessel_j_ex(x, -alpha, by) * sinpi(alpha)));
126  }
127  else if (alpha > 1e7) {
128  MATHLIB_WARNING(_("besselY(x, nu): nu=%g too large for bessel_y() algorithm"),
129  alpha);
130  return ML_NAN;
131  }
132  nb = 1+ (int)trunc(na);/* nb-1 <= alpha < nb */
133  alpha -= (double)(nb-1);
134  Y_bessel(&x, &alpha, &nb, by, &ncalc);
135  if(ncalc != nb) {/* error input */
136  if(ncalc == -1)
137  return ML_POSINF;
138  else if(ncalc < -1)
139  MATHLIB_WARNING4(_("bessel_y(%g): ncalc (=%d) != nb (=%d); alpha=%g. Arg. out of range?\n"),
140  x, ncalc, nb, alpha);
141  else /* ncalc >= 0 */
142  MATHLIB_WARNING2(_("bessel_y(%g,nu=%g): precision lost in result\n"),
143  x, alpha+(double)nb-1);
144  }
145  x = by[nb-1];
146  return x;
147 }
148 
149 template<class Float>
150 static void Y_bessel(Float *x, Float *alpha, int *nb,
151  Float *by, int *ncalc)
152 {
153 /* ----------------------------------------------------------------------
154 
155  This routine calculates Bessel functions Y_(N+ALPHA) (X)
156 v for non-negative argument X, and non-negative order N+ALPHA.
157 
158 
159  Explanation of variables in the calling sequence
160 
161  X - Non-negative argument for which
162  Y's are to be calculated.
163  ALPHA - Fractional part of order for which
164  Y's are to be calculated. 0 <= ALPHA < 1.0.
165  NB - Number of functions to be calculated, NB > 0.
166  The first function calculated is of order ALPHA, and the
167  last is of order (NB - 1 + ALPHA).
168  BY - Output vector of length NB. If the
169  routine terminates normally (NCALC=NB), the vector BY
170  contains the functions Y(ALPHA,X), ... , Y(NB-1+ALPHA,X),
171  If (0 < NCALC < NB), BY(I) contains correct function
172  values for I <= NCALC, and contains the ratios
173  Y(ALPHA+I-1,X)/Y(ALPHA+I-2,X) for the rest of the array.
174  NCALC - Output variable indicating possible errors.
175  Before using the vector BY, the user should check that
176  NCALC=NB, i.e., all orders have been calculated to
177  the desired accuracy. See error returns below.
178 
179 
180  *******************************************************************
181 
182  Error returns
183 
184  In case of an error, NCALC != NB, and not all Y's are
185  calculated to the desired accuracy.
186 
187  NCALC < -1: An argument is out of range. For example,
188  NB <= 0, IZE is not 1 or 2, or IZE=1 and ABS(X) >=
189  XMAX. In this case, BY[0] = 0.0, the remainder of the
190  BY-vector is not calculated, and NCALC is set to
191  MIN0(NB,0)-2 so that NCALC != NB.
192  NCALC = -1: Y(ALPHA,X) >= XINF. The requested function
193  values are set to 0.0.
194  1 < NCALC < NB: Not all requested function values could
195  be calculated accurately. BY(I) contains correct function
196  values for I <= NCALC, and and the remaining NB-NCALC
197  array elements contain 0.0.
198 
199 
200  Intrinsic functions required are:
201 
202  DBLE, EXP, INT, MAX, MIN, REAL, SQRT
203 
204 
205  Acknowledgement
206 
207  This program draws heavily on Temme's Algol program for Y(a,x)
208  and Y(a+1,x) and on Campbell's programs for Y_nu(x). Temme's
209  scheme is used for x < THRESH, and Campbell's scheme is used
210  in the asymptotic region. Segments of code from both sources
211  have been translated into Fortran 77, merged, and heavily modified.
212  Modifications include parameterization of machine dependencies,
213  use of a new approximation for ln(gamma(x)), and built-in
214  protection against over/underflow.
215 
216  References: "Bessel functions J_nu(x) and Y_nu(x) of float
217  order and float argument," Campbell, J. B.,
218  Comp. Phy. Comm. 18, 1979, pp. 133-142.
219 
220  "On the numerical evaluation of the ordinary
221  Bessel function of the second kind," Temme,
222  N. M., J. Comput. Phys. 21, 1976, pp. 343-350.
223 
224  Latest modification: March 19, 1990
225 
226  Modified by: W. J. Cody
227  Applied Mathematics Division
228  Argonne National Laboratory
229  Argonne, IL 60439
230  ----------------------------------------------------------------------*/
231 
232 
233 /* ----------------------------------------------------------------------
234  Mathematical constants
235  FIVPI = 5*PI
236  PIM5 = 5*PI - 15
237  ----------------------------------------------------------------------*/
238  const static double fivpi = 15.707963267948966192;
239  const static double pim5 = .70796326794896619231;
240 
241  /*----------------------------------------------------------------------
242  Coefficients for Chebyshev polynomial expansion of
243  1/gamma(1-x), abs(x) <= .5
244  ----------------------------------------------------------------------*/
245  const static double ch[21] = { -6.7735241822398840964e-24,
246  -6.1455180116049879894e-23,2.9017595056104745456e-21,
247  1.3639417919073099464e-19,2.3826220476859635824e-18,
248  -9.0642907957550702534e-18,-1.4943667065169001769e-15,
249  -3.3919078305362211264e-14,-1.7023776642512729175e-13,
250  9.1609750938768647911e-12,2.4230957900482704055e-10,
251  1.7451364971382984243e-9,-3.3126119768180852711e-8,
252  -8.6592079961391259661e-7,-4.9717367041957398581e-6,
253  7.6309597585908126618e-5,.0012719271366545622927,
254  .0017063050710955562222,-.07685284084478667369,
255  -.28387654227602353814,.92187029365045265648 };
256 
257  /* Local variables */
258  int i, k, na;
259 
260  Float alfa, div, ddiv, even, gamma, term, cosmu, sinmu,
261  b, c, d, e, f, g, h, p, q, r, s, d1, d2, q0, pa,pa1, qa,qa1,
262  en, en1, nu, ex, ya,ya1, twobyx, den, odd, aye, dmu, x2, xna;
263 
264  en1 = ya = ya1 = 0; /* -Wall */
265 
266  ex = *x;
267  nu = *alpha;
268  if (*nb > 0 && 0. <= nu && nu < 1.) {
269  if(ex < DBL_MIN || ex > xlrg_BESS_Y) {
270  /* Warning is not really appropriate, give
271  * proper limit:
272  * ML_ERROR(ME_RANGE, "Y_bessel"); */
273  *ncalc = *nb;
274  if(ex > xlrg_BESS_Y) by[0]= 0.; /*was ML_POSINF */
275  else if(ex < DBL_MIN) by[0]=ML_NEGINF;
276  for(i=0; i < *nb; i++)
277  by[i] = by[0];
278  return;
279  }
280  xna = trunc(nu + .5);
281  na = (int) trunc(xna);
282  if (na == 1) {/* <==> .5 <= *alpha < 1 <==> -5. <= nu < 0 */
283  nu -= xna;
284  }
285  // Kasper: This special case ignores derivatives wrt. nu. We must
286  // squeeze it into the general case (even if it might be slower).
287  // if (nu == -.5) {
288  // p = M_SQRT_2dPI / sqrt(ex);
289  // ya = p * sin(ex);
290  // ya1 = -p * cos(ex);
291  // } else
292  if (ex < 3.) {
293  /* -------------------------------------------------------------
294  Use Temme's scheme for small X
295  ------------------------------------------------------------- */
296  b = ex * .5;
297  d = -log(b);
298  f = nu * d;
299  e = pow(b, -nu);
300  if (fabs(nu) < M_eps_sinc)
301  // Kasper: Improve approximation near zero
302  // c = M_1_PI;
303  c = M_1_PI / ( 1. - (M_PI * M_PI / 6.) * nu * nu );
304  else
305  c = nu / sinpi(nu);
306 
307  /* ------------------------------------------------------------
308  Computation of sinh(f)/f
309  ------------------------------------------------------------ */
310  if (fabs(f) < 1.) {
311  x2 = f * f;
312  en = 19.;
313  s = 1.;
314  for (i = 1; i <= 9; ++i) {
315  s = s * x2 / en / (en - 1.) + 1.;
316  en -= 2.;
317  }
318  } else {
319  s = (e - 1. / e) * .5 / f;
320  }
321  /* --------------------------------------------------------
322  Computation of 1/gamma(1-a) using Chebyshev polynomials */
323  x2 = nu * nu * 8.;
324  aye = ch[0];
325  even = 0.;
326  alfa = ch[1];
327  odd = 0.;
328  for (i = 3; i <= 19; i += 2) {
329  even = -(aye + aye + even);
330  aye = -even * x2 - aye + ch[i - 1];
331  odd = -(alfa + alfa + odd);
332  alfa = -odd * x2 - alfa + ch[i];
333  }
334  even = (even * .5 + aye) * x2 - aye + ch[20];
335  odd = (odd + alfa) * 2.;
336  gamma = odd * nu + even;
337  /* End of computation of 1/gamma(1-a)
338  ----------------------------------------------------------- */
339  g = e * gamma;
340  e = (e + 1. / e) * .5;
341  f = 2. * c * (odd * e + even * s * d);
342  e = nu * nu;
343  p = g * c;
344  q = M_1_PI / g;
345  c = nu * M_PI_2;
346  if (fabs(c) < M_eps_sinc)
347  r = 1.;
348  else
349  r = sinpi(nu/2) / c;
350 
351  r = M_PI * c * r * r;
352  c = 1.;
353  d = -b * b;
354  h = 0.;
355  ya = f + r * q;
356  ya1 = p;
357  en = 1.;
358 
359  while (fabs(g / (1. + fabs(ya))) +
360  fabs(h / (1. + fabs(ya1))) > DBL_EPSILON) {
361  f = (f * en + p + q) / (en * en - e);
362  c *= (d / en);
363  p /= en - nu;
364  q /= en + nu;
365  g = c * (f + r * q);
366  h = c * p - en * g;
367  ya += g;
368  ya1+= h;
369  en += 1.;
370  }
371  ya = -ya;
372  ya1 = -ya1 / b;
373  } else if (ex < thresh_BESS_Y) {
374  /* --------------------------------------------------------------
375  Use Temme's scheme for moderate X : 3 <= x < 16
376  -------------------------------------------------------------- */
377  c = (.5 - nu) * (.5 + nu);
378  b = ex + ex;
379  // Kasper: nu=-.5 ==> cospi(nu)=0 ==> zero iterations !
380  // We must increase e in this case.
381  // e = ex * M_1_PI * cospi(nu) / DBL_EPSILON;
382  double tiny = 1e-4;
383  e = ex * M_1_PI * ( fabs(cospi(nu)) + tiny ) / (1. + tiny) / DBL_EPSILON;
384  e *= e;
385  p = 1.;
386  q = -ex;
387  r = 1. + ex * ex;
388  s = r;
389  en = 2.;
390  while (r * en * en < e) {
391  en1 = en + 1.;
392  d = (en - 1. + c / en) / s;
393  p = (en + en - p * d) / en1;
394  q = (-b + q * d) / en1;
395  s = p * p + q * q;
396  r *= s;
397  en = en1;
398  }
399  f = p / s;
400  p = f;
401  g = -q / s;
402  q = g;
403 L220:
404  en -= 1.;
405  if (en > 0.) {
406  r = en1 * (2. - p) - 2.;
407  s = b + en1 * q;
408  d = (en - 1. + c / en) / (r * r + s * s);
409  p = d * r;
410  q = d * s;
411  e = f + 1.;
412  f = p * e - g * q;
413  g = q * e + p * g;
414  en1 = en;
415  goto L220;
416  }
417  f = 1. + f;
418  d = f * f + g * g;
419  pa = f / d;
420  qa = -g / d;
421  d = nu + .5 - p;
422  q += ex;
423  pa1 = (pa * q - qa * d) / ex;
424  qa1 = (qa * q + pa * d) / ex;
425  b = ex - M_PI_2 * (nu + .5);
426  c = cos(b);
427  s = sin(b);
428  d = M_SQRT_2dPI / sqrt(ex);
429  ya = d * (pa * s + qa * c);
430  ya1 = d * (qa1 * s - pa1 * c);
431  } else { /* x > thresh_BESS_Y */
432  /* ----------------------------------------------------------
433  Use Campbell's asymptotic scheme.
434  ---------------------------------------------------------- */
435  na = 0;
436  d1 = trunc(ex / fivpi);
437  i = (int) trunc(d1);
438  dmu = ex - 15. * d1 - d1 * pim5 - (*alpha + .5) * M_PI_2;
439  if (i - (i / 2 << 1) == 0) {
440  cosmu = cos(dmu);
441  sinmu = sin(dmu);
442  } else {
443  cosmu = -cos(dmu);
444  sinmu = -sin(dmu);
445  }
446  ddiv = 8. * ex;
447  dmu = *alpha;
448  den = sqrt(ex);
449  for (k = 1; k <= 2; ++k) {
450  p = cosmu;
451  cosmu = sinmu;
452  sinmu = -p;
453  d1 = (2. * dmu - 1.) * (2. * dmu + 1.);
454  d2 = 0.;
455  div = ddiv;
456  p = 0.;
457  q = 0.;
458  q0 = d1 / div;
459  term = q0;
460  for (i = 2; i <= 20; ++i) {
461  d2 += 8.;
462  d1 -= d2;
463  div += ddiv;
464  term = -term * d1 / div;
465  p += term;
466  d2 += 8.;
467  d1 -= d2;
468  div += ddiv;
469  term *= (d1 / div);
470  q += term;
471  if (fabs(term) <= DBL_EPSILON) {
472  break;
473  }
474  }
475  p += 1.;
476  q += q0;
477  if (k == 1)
478  ya = M_SQRT_2dPI * (p * cosmu - q * sinmu) / den;
479  else
480  ya1 = M_SQRT_2dPI * (p * cosmu - q * sinmu) / den;
481  dmu += 1.;
482  }
483  }
484  if (na == 1) {
485  h = 2. * (nu + 1.) / ex;
486  if (h > 1.) {
487  if (fabs(ya1) > DBL_MAX / h) {
488  h = 0.;
489  ya = 0.;
490  }
491  }
492  h = h * ya1 - ya;
493  ya = ya1;
494  ya1 = h;
495  }
496 
497  /* ---------------------------------------------------------------
498  Now have first one or two Y's
499  --------------------------------------------------------------- */
500  by[0] = ya;
501  *ncalc = 1;
502  if(*nb > 1) {
503  by[1] = ya1;
504  if (ya1 != 0.) {
505  aye = 1. + *alpha;
506  twobyx = 2. / ex;
507  *ncalc = 2;
508  for (i = 2; i < *nb; ++i) {
509  if (twobyx < 1.) {
510  if (fabs(by[i - 1]) * twobyx >= DBL_MAX / aye)
511  goto L450;
512  } else {
513  if (fabs(by[i - 1]) >= DBL_MAX / aye / twobyx)
514  goto L450;
515  }
516  by[i] = twobyx * aye * by[i - 1] - by[i - 2];
517  aye += 1.;
518  ++(*ncalc);
519  }
520  }
521  }
522 L450:
523  for (i = *ncalc; i < *nb; ++i)
524  by[i] = ML_NEGINF;/* was 0 */
525 
526  } else {
527  by[0] = 0.;
528  *ncalc = min0(*nb,0) - 1;
529  }
530 }
531 
License: GPL v2