gsl_specfunc__bessel_sequence.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* specfunc/bessel_sequence.c
  2. *
  3. * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
  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 3 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * 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, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. /* Author: G. Jungman */
  20. #include "gsl__config.h"
  21. #include "gsl_math.h"
  22. #include "gsl_errno.h"
  23. #include "gsl_sf_bessel.h"
  24. #define DYDX_p(p,u,x) (-(p)/(x) + (((nu)*(nu))/((x)*(x))-1.0)*(u))
  25. #define DYDX_u(p,u,x) (p)
  26. static int
  27. rk_step(double nu, double x, double dx, double * Jp, double * J)
  28. {
  29. double p_0 = *Jp;
  30. double u_0 = *J;
  31. double p_1 = dx * DYDX_p(p_0, u_0, x);
  32. double u_1 = dx * DYDX_u(p_0, u_0, x);
  33. double p_2 = dx * DYDX_p(p_0 + 0.5*p_1, u_0 + 0.5*u_1, x + 0.5*dx);
  34. double u_2 = dx * DYDX_u(p_0 + 0.5*p_1, u_0 + 0.5*u_1, x + 0.5*dx);
  35. double p_3 = dx * DYDX_p(p_0 + 0.5*p_2, u_0 + 0.5*u_2, x + 0.5*dx);
  36. double u_3 = dx * DYDX_u(p_0 + 0.5*p_2, u_0 + 0.5*u_2, x + 0.5*dx);
  37. double p_4 = dx * DYDX_p(p_0 + p_3, u_0 + u_3, x + dx);
  38. double u_4 = dx * DYDX_u(p_0 + p_3, u_0 + u_3, x + dx);
  39. *Jp = p_0 + p_1/6.0 + p_2/3.0 + p_3/3.0 + p_4/6.0;
  40. *J = u_0 + u_1/6.0 + u_2/3.0 + u_3/3.0 + u_4/6.0;
  41. return GSL_SUCCESS;
  42. }
  43. int
  44. gsl_sf_bessel_sequence_Jnu_e(double nu, gsl_mode_t mode, size_t size, double * v)
  45. {
  46. /* CHECK_POINTER(v) */
  47. if(nu < 0.0) {
  48. GSL_ERROR ("domain error", GSL_EDOM);
  49. }
  50. else if(size == 0) {
  51. GSL_ERROR ("error", GSL_EINVAL);
  52. }
  53. else {
  54. const gsl_prec_t goal = GSL_MODE_PREC(mode);
  55. const double dx_array[] = { 0.001, 0.03, 0.1 }; /* double, single, approx */
  56. const double dx_nominal = dx_array[goal];
  57. const int cnu = (int) ceil(nu);
  58. const double nu13 = pow(nu,1.0/3.0);
  59. const double smalls[] = { 0.01, 0.02, 0.4, 0.7, 1.3, 2.0, 2.5, 3.2, 3.5, 4.5, 6.0 };
  60. const double x_small = ( nu >= 10.0 ? nu - nu13 : smalls[cnu] );
  61. gsl_sf_result J0, J1;
  62. double Jp, J;
  63. double x;
  64. size_t i = 0;
  65. /* Calculate the first point. */
  66. x = v[0];
  67. gsl_sf_bessel_Jnu_e(nu, x, &J0);
  68. v[0] = J0.val;
  69. ++i;
  70. /* Step over the idiot case where the
  71. * first point was actually zero.
  72. */
  73. if(x == 0.0) {
  74. if(v[1] <= x) {
  75. /* Strict ordering failure. */
  76. GSL_ERROR ("error", GSL_EFAILED);
  77. }
  78. x = v[1];
  79. gsl_sf_bessel_Jnu_e(nu, x, &J0);
  80. v[1] = J0.val;
  81. ++i;
  82. }
  83. /* Calculate directly as long as the argument
  84. * is small. This is necessary because the
  85. * integration is not very good there.
  86. */
  87. while(v[i] < x_small && i < size) {
  88. if(v[i] <= x) {
  89. /* Strict ordering failure. */
  90. GSL_ERROR ("error", GSL_EFAILED);
  91. }
  92. x = v[i];
  93. gsl_sf_bessel_Jnu_e(nu, x, &J0);
  94. v[i] = J0.val;
  95. ++i;
  96. }
  97. /* At this point we are ready to integrate.
  98. * The value of x is the last calculated
  99. * point, which has the value J0; v[i] is
  100. * the next point we need to calculate. We
  101. * calculate nu+1 at x as well to get
  102. * the derivative, then we go forward.
  103. */
  104. gsl_sf_bessel_Jnu_e(nu+1.0, x, &J1);
  105. J = J0.val;
  106. Jp = -J1.val + nu/x * J0.val;
  107. while(i < size) {
  108. const double dv = v[i] - x;
  109. const int Nd = (int) ceil(dv/dx_nominal);
  110. const double dx = dv / Nd;
  111. double xj;
  112. int j;
  113. if(v[i] <= x) {
  114. /* Strict ordering failure. */
  115. GSL_ERROR ("error", GSL_EFAILED);
  116. }
  117. /* Integrate over interval up to next sample point.
  118. */
  119. for(j=0, xj=x; j<Nd; j++, xj += dx) {
  120. rk_step(nu, xj, dx, &Jp, &J);
  121. }
  122. /* Go to next interval. */
  123. x = v[i];
  124. v[i] = J;
  125. ++i;
  126. }
  127. return GSL_SUCCESS;
  128. }
  129. }