gsl_specfunc__legendre_H3d.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /* specfunc/legendre_H3d.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_exp.h"
  24. #include "gsl_sf_gamma.h"
  25. #include "gsl_sf_trig.h"
  26. #include "gsl_sf_legendre.h"
  27. #include "gsl_specfunc__error.h"
  28. #include "gsl_specfunc__legendre.h"
  29. /* See [Abbott+Schaefer, Ap.J. 308, 546 (1986)] for
  30. * enough details to follow what is happening here.
  31. */
  32. /* Logarithm of normalization factor, Log[N(ell,lambda)].
  33. * N(ell,lambda) = Product[ lambda^2 + n^2, {n,0,ell} ]
  34. * = |Gamma(ell + 1 + I lambda)|^2 lambda sinh(Pi lambda) / Pi
  35. * Assumes ell >= 0.
  36. */
  37. static
  38. int
  39. legendre_H3d_lnnorm(const int ell, const double lambda, double * result)
  40. {
  41. double abs_lam = fabs(lambda);
  42. if(abs_lam == 0.0) {
  43. *result = 0.0;
  44. GSL_ERROR ("error", GSL_EDOM);
  45. }
  46. else if(lambda > (ell + 1.0)/GSL_ROOT3_DBL_EPSILON) {
  47. /* There is a cancellation between the sinh(Pi lambda)
  48. * term and the log(gamma(ell + 1 + i lambda) in the
  49. * result below, so we show some care and save some digits.
  50. * Note that the above guarantees that lambda is large,
  51. * since ell >= 0. We use Stirling and a simple expansion
  52. * of sinh.
  53. */
  54. double rat = (ell+1.0)/lambda;
  55. double ln_lam2ell2 = 2.0*log(lambda) + log(1.0 + rat*rat);
  56. double lg_corrected = -2.0*(ell+1.0) + M_LNPI + (ell+0.5)*ln_lam2ell2 + 1.0/(288.0*lambda*lambda);
  57. double angle_terms = lambda * 2.0 * rat * (1.0 - rat*rat/3.0);
  58. *result = log(abs_lam) + lg_corrected + angle_terms - M_LNPI;
  59. return GSL_SUCCESS;
  60. }
  61. else {
  62. gsl_sf_result lg_r;
  63. gsl_sf_result lg_theta;
  64. gsl_sf_result ln_sinh;
  65. gsl_sf_lngamma_complex_e(ell+1.0, lambda, &lg_r, &lg_theta);
  66. gsl_sf_lnsinh_e(M_PI * abs_lam, &ln_sinh);
  67. *result = log(abs_lam) + ln_sinh.val + 2.0*lg_r.val - M_LNPI;
  68. return GSL_SUCCESS;
  69. }
  70. }
  71. /* Calculate series for small eta*lambda.
  72. * Assumes eta > 0, lambda != 0.
  73. *
  74. * This is just the defining hypergeometric for the Legendre function.
  75. *
  76. * P^{mu}_{-1/2 + I lam}(z) = 1/Gamma(l+3/2) ((z+1)/(z-1)^(mu/2)
  77. * 2F1(1/2 - I lam, 1/2 + I lam; l+3/2; (1-z)/2)
  78. * We use
  79. * z = cosh(eta)
  80. * (z-1)/2 = sinh^2(eta/2)
  81. *
  82. * And recall
  83. * H3d = sqrt(Pi Norm /(2 lam^2 sinh(eta))) P^{-l-1/2}_{-1/2 + I lam}(cosh(eta))
  84. */
  85. static
  86. int
  87. legendre_H3d_series(const int ell, const double lambda, const double eta,
  88. gsl_sf_result * result)
  89. {
  90. const int nmax = 5000;
  91. const double shheta = sinh(0.5*eta);
  92. const double ln_zp1 = M_LN2 + log(1.0 + shheta*shheta);
  93. const double ln_zm1 = M_LN2 + 2.0*log(shheta);
  94. const double zeta = -shheta*shheta;
  95. gsl_sf_result lg_lp32;
  96. double term = 1.0;
  97. double sum = 1.0;
  98. double sum_err = 0.0;
  99. gsl_sf_result lnsheta;
  100. double lnN;
  101. double lnpre_val, lnpre_err, lnprepow;
  102. int stat_e;
  103. int n;
  104. gsl_sf_lngamma_e(ell + 3.0/2.0, &lg_lp32);
  105. gsl_sf_lnsinh_e(eta, &lnsheta);
  106. legendre_H3d_lnnorm(ell, lambda, &lnN);
  107. lnprepow = 0.5*(ell + 0.5) * (ln_zm1 - ln_zp1);
  108. lnpre_val = lnprepow + 0.5*(lnN + M_LNPI - M_LN2 - lnsheta.val) - lg_lp32.val - log(fabs(lambda));
  109. lnpre_err = lnsheta.err + lg_lp32.err + GSL_DBL_EPSILON * fabs(lnpre_val);
  110. lnpre_err += 2.0*GSL_DBL_EPSILON * (fabs(lnN) + M_LNPI + M_LN2);
  111. lnpre_err += 2.0*GSL_DBL_EPSILON * (0.5*(ell + 0.5) * (fabs(ln_zm1) + fabs(ln_zp1)));
  112. for(n=1; n<nmax; n++) {
  113. double aR = n - 0.5;
  114. term *= (aR*aR + lambda*lambda)*zeta/(ell + n + 0.5)/n;
  115. sum += term;
  116. sum_err += 2.0*GSL_DBL_EPSILON*fabs(term);
  117. if(fabs(term/sum) < 2.0 * GSL_DBL_EPSILON) break;
  118. }
  119. stat_e = gsl_sf_exp_mult_err_e(lnpre_val, lnpre_err, sum, fabs(term)+sum_err, result);
  120. return GSL_ERROR_SELECT_2(stat_e, (n==nmax ? GSL_EMAXITER : GSL_SUCCESS));
  121. }
  122. /* Evaluate legendre_H3d(ell+1)/legendre_H3d(ell)
  123. * by continued fraction.
  124. */
  125. #if 0
  126. static
  127. int
  128. legendre_H3d_CF1(const int ell, const double lambda, const double coth_eta,
  129. gsl_sf_result * result)
  130. {
  131. const double RECUR_BIG = GSL_SQRT_DBL_MAX;
  132. const int maxiter = 5000;
  133. int n = 1;
  134. double Anm2 = 1.0;
  135. double Bnm2 = 0.0;
  136. double Anm1 = 0.0;
  137. double Bnm1 = 1.0;
  138. double a1 = hypot(lambda, ell+1.0);
  139. double b1 = (2.0*ell + 3.0) * coth_eta;
  140. double An = b1*Anm1 + a1*Anm2;
  141. double Bn = b1*Bnm1 + a1*Bnm2;
  142. double an, bn;
  143. double fn = An/Bn;
  144. while(n < maxiter) {
  145. double old_fn;
  146. double del;
  147. n++;
  148. Anm2 = Anm1;
  149. Bnm2 = Bnm1;
  150. Anm1 = An;
  151. Bnm1 = Bn;
  152. an = -(lambda*lambda + ((double)ell + n)*((double)ell + n));
  153. bn = (2.0*ell + 2.0*n + 1.0) * coth_eta;
  154. An = bn*Anm1 + an*Anm2;
  155. Bn = bn*Bnm1 + an*Bnm2;
  156. if(fabs(An) > RECUR_BIG || fabs(Bn) > RECUR_BIG) {
  157. An /= RECUR_BIG;
  158. Bn /= RECUR_BIG;
  159. Anm1 /= RECUR_BIG;
  160. Bnm1 /= RECUR_BIG;
  161. Anm2 /= RECUR_BIG;
  162. Bnm2 /= RECUR_BIG;
  163. }
  164. old_fn = fn;
  165. fn = An/Bn;
  166. del = old_fn/fn;
  167. if(fabs(del - 1.0) < 4.0*GSL_DBL_EPSILON) break;
  168. }
  169. result->val = fn;
  170. result->err = 2.0 * GSL_DBL_EPSILON * (sqrt(n)+1.0) * fabs(fn);
  171. if(n >= maxiter)
  172. GSL_ERROR ("error", GSL_EMAXITER);
  173. else
  174. return GSL_SUCCESS;
  175. }
  176. #endif /* 0 */
  177. /* Evaluate legendre_H3d(ell+1)/legendre_H3d(ell)
  178. * by continued fraction. Use the Gautschi (Euler)
  179. * equivalent series.
  180. */
  181. /* FIXME: Maybe we have to worry about this. The a_k are
  182. * not positive and there can be a blow-up. It happened
  183. * for J_nu once or twice. Then we should probably use
  184. * the method above.
  185. */
  186. static
  187. int
  188. legendre_H3d_CF1_ser(const int ell, const double lambda, const double coth_eta,
  189. gsl_sf_result * result)
  190. {
  191. const double pre = hypot(lambda, ell+1.0)/((2.0*ell+3)*coth_eta);
  192. const int maxk = 20000;
  193. double tk = 1.0;
  194. double sum = 1.0;
  195. double rhok = 0.0;
  196. double sum_err = 0.0;
  197. int k;
  198. for(k=1; k<maxk; k++) {
  199. double tlk = (2.0*ell + 1.0 + 2.0*k);
  200. double l1k = (ell + 1.0 + k);
  201. double ak = -(lambda*lambda + l1k*l1k)/(tlk*(tlk+2.0)*coth_eta*coth_eta);
  202. rhok = -ak*(1.0 + rhok)/(1.0 + ak*(1.0 + rhok));
  203. tk *= rhok;
  204. sum += tk;
  205. sum_err += 2.0 * GSL_DBL_EPSILON * k * fabs(tk);
  206. if(fabs(tk/sum) < GSL_DBL_EPSILON) break;
  207. }
  208. result->val = pre * sum;
  209. result->err = fabs(pre * tk);
  210. result->err += fabs(pre * sum_err);
  211. result->err += 4.0 * GSL_DBL_EPSILON * fabs(result->val);
  212. if(k >= maxk)
  213. GSL_ERROR ("error", GSL_EMAXITER);
  214. else
  215. return GSL_SUCCESS;
  216. }
  217. /*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/
  218. int
  219. gsl_sf_legendre_H3d_0_e(const double lambda, const double eta, gsl_sf_result * result)
  220. {
  221. /* CHECK_POINTER(result) */
  222. if(eta < 0.0) {
  223. DOMAIN_ERROR(result);
  224. }
  225. else if(eta == 0.0 || lambda == 0.0) {
  226. result->val = 1.0;
  227. result->err = 0.0;
  228. return GSL_SUCCESS;
  229. }
  230. else {
  231. const double lam_eta = lambda * eta;
  232. gsl_sf_result s;
  233. gsl_sf_sin_err_e(lam_eta, 2.0*GSL_DBL_EPSILON * fabs(lam_eta), &s);
  234. if(eta > -0.5*GSL_LOG_DBL_EPSILON) {
  235. double f = 2.0 / lambda * exp(-eta);
  236. result->val = f * s.val;
  237. result->err = fabs(f * s.val) * (fabs(eta) + 1.0) * GSL_DBL_EPSILON;
  238. result->err += fabs(f) * s.err;
  239. result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
  240. }
  241. else {
  242. double f = 1.0/(lambda*sinh(eta));
  243. result->val = f * s.val;
  244. result->err = fabs(f * s.val) * (fabs(eta) + 1.0) * GSL_DBL_EPSILON;
  245. result->err += fabs(f) * s.err;
  246. result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
  247. }
  248. return GSL_SUCCESS;
  249. }
  250. }
  251. int
  252. gsl_sf_legendre_H3d_1_e(const double lambda, const double eta, gsl_sf_result * result)
  253. {
  254. const double xi = fabs(eta*lambda);
  255. const double lsq = lambda*lambda;
  256. const double lsqp1 = lsq + 1.0;
  257. /* CHECK_POINTER(result) */
  258. if(eta < 0.0) {
  259. DOMAIN_ERROR(result);
  260. }
  261. else if(eta == 0.0 || lambda == 0.0) {
  262. result->val = 0.0;
  263. result->err = 0.0;
  264. return GSL_SUCCESS;
  265. }
  266. else if(xi < GSL_ROOT5_DBL_EPSILON && eta < GSL_ROOT5_DBL_EPSILON) {
  267. double etasq = eta*eta;
  268. double xisq = xi*xi;
  269. double term1 = (etasq + xisq)/3.0;
  270. double term2 = -(2.0*etasq*etasq + 5.0*etasq*xisq + 3.0*xisq*xisq)/90.0;
  271. double sinh_term = 1.0 - eta*eta/6.0 * (1.0 - 7.0/60.0*eta*eta);
  272. double pre = sinh_term/sqrt(lsqp1) / eta;
  273. result->val = pre * (term1 + term2);
  274. result->err = pre * GSL_DBL_EPSILON * (fabs(term1) + fabs(term2));
  275. result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
  276. return GSL_SUCCESS;
  277. }
  278. else {
  279. double sin_term; /* Sin(xi)/xi */
  280. double cos_term; /* Cos(xi) */
  281. double coth_term; /* eta/Tanh(eta) */
  282. double sinh_term; /* eta/Sinh(eta) */
  283. double sin_term_err;
  284. double cos_term_err;
  285. double t1;
  286. double pre_val;
  287. double pre_err;
  288. double term1;
  289. double term2;
  290. if(xi < GSL_ROOT5_DBL_EPSILON) {
  291. sin_term = 1.0 - xi*xi/6.0 * (1.0 - xi*xi/20.0);
  292. cos_term = 1.0 - 0.5*xi*xi * (1.0 - xi*xi/12.0);
  293. sin_term_err = GSL_DBL_EPSILON;
  294. cos_term_err = GSL_DBL_EPSILON;
  295. }
  296. else {
  297. gsl_sf_result sin_xi_result;
  298. gsl_sf_result cos_xi_result;
  299. gsl_sf_sin_e(xi, &sin_xi_result);
  300. gsl_sf_cos_e(xi, &cos_xi_result);
  301. sin_term = sin_xi_result.val/xi;
  302. cos_term = cos_xi_result.val;
  303. sin_term_err = sin_xi_result.err/fabs(xi);
  304. cos_term_err = cos_xi_result.err;
  305. }
  306. if(eta < GSL_ROOT5_DBL_EPSILON) {
  307. coth_term = 1.0 + eta*eta/3.0 * (1.0 - eta*eta/15.0);
  308. sinh_term = 1.0 - eta*eta/6.0 * (1.0 - 7.0/60.0*eta*eta);
  309. }
  310. else {
  311. coth_term = eta/tanh(eta);
  312. sinh_term = eta/sinh(eta);
  313. }
  314. t1 = sqrt(lsqp1) * eta;
  315. pre_val = sinh_term/t1;
  316. pre_err = 2.0 * GSL_DBL_EPSILON * fabs(pre_val);
  317. term1 = sin_term*coth_term;
  318. term2 = cos_term;
  319. result->val = pre_val * (term1 - term2);
  320. result->err = pre_err * fabs(term1 - term2);
  321. result->err += pre_val * (sin_term_err * coth_term + cos_term_err);
  322. result->err += pre_val * fabs(term1-term2) * (fabs(eta) + 1.0) * GSL_DBL_EPSILON;
  323. result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
  324. return GSL_SUCCESS;
  325. }
  326. }
  327. int
  328. gsl_sf_legendre_H3d_e(const int ell, const double lambda, const double eta,
  329. gsl_sf_result * result)
  330. {
  331. const double abs_lam = fabs(lambda);
  332. const double lsq = abs_lam*abs_lam;
  333. const double xi = abs_lam * eta;
  334. const double cosh_eta = cosh(eta);
  335. /* CHECK_POINTER(result) */
  336. if(eta < 0.0) {
  337. DOMAIN_ERROR(result);
  338. }
  339. else if(eta > GSL_LOG_DBL_MAX) {
  340. /* cosh(eta) is too big. */
  341. OVERFLOW_ERROR(result);
  342. }
  343. else if(ell == 0) {
  344. return gsl_sf_legendre_H3d_0_e(lambda, eta, result);
  345. }
  346. else if(ell == 1) {
  347. return gsl_sf_legendre_H3d_1_e(lambda, eta, result);
  348. }
  349. else if(eta == 0.0) {
  350. result->val = 0.0;
  351. result->err = 0.0;
  352. return GSL_SUCCESS;
  353. }
  354. else if(xi < 1.0) {
  355. return legendre_H3d_series(ell, lambda, eta, result);
  356. }
  357. else if((ell*ell+lsq)/sqrt(1.0+lsq)/(cosh_eta*cosh_eta) < 5.0*GSL_ROOT3_DBL_EPSILON) {
  358. /* Large argument.
  359. */
  360. gsl_sf_result P;
  361. double lm;
  362. int stat_P = gsl_sf_conicalP_large_x_e(-ell-0.5, lambda, cosh_eta, &P, &lm);
  363. if(P.val == 0.0) {
  364. result->val = 0.0;
  365. result->err = 0.0;
  366. return stat_P;
  367. }
  368. else {
  369. double lnN;
  370. gsl_sf_result lnsh;
  371. double ln_abslam;
  372. double lnpre_val, lnpre_err;
  373. int stat_e;
  374. gsl_sf_lnsinh_e(eta, &lnsh);
  375. legendre_H3d_lnnorm(ell, lambda, &lnN);
  376. ln_abslam = log(abs_lam);
  377. lnpre_val = 0.5*(M_LNPI + lnN - M_LN2 - lnsh.val) - ln_abslam;
  378. lnpre_err = lnsh.err;
  379. lnpre_err += 2.0 * GSL_DBL_EPSILON * (0.5*(M_LNPI + M_LN2 + fabs(lnN)) + fabs(ln_abslam));
  380. lnpre_err += 2.0 * GSL_DBL_EPSILON * fabs(lnpre_val);
  381. stat_e = gsl_sf_exp_mult_err_e(lnpre_val + lm, lnpre_err, P.val, P.err, result);
  382. return GSL_ERROR_SELECT_2(stat_e, stat_P);
  383. }
  384. }
  385. else if(abs_lam > 1000.0*ell*ell) {
  386. /* Large degree.
  387. */
  388. gsl_sf_result P;
  389. double lm;
  390. int stat_P = gsl_sf_conicalP_xgt1_neg_mu_largetau_e(ell+0.5,
  391. lambda,
  392. cosh_eta, eta,
  393. &P, &lm);
  394. if(P.val == 0.0) {
  395. result->val = 0.0;
  396. result->err = 0.0;
  397. return stat_P;
  398. }
  399. else {
  400. double lnN;
  401. gsl_sf_result lnsh;
  402. double ln_abslam;
  403. double lnpre_val, lnpre_err;
  404. int stat_e;
  405. gsl_sf_lnsinh_e(eta, &lnsh);
  406. legendre_H3d_lnnorm(ell, lambda, &lnN);
  407. ln_abslam = log(abs_lam);
  408. lnpre_val = 0.5*(M_LNPI + lnN - M_LN2 - lnsh.val) - ln_abslam;
  409. lnpre_err = lnsh.err;
  410. lnpre_err += GSL_DBL_EPSILON * (0.5*(M_LNPI + M_LN2 + fabs(lnN)) + fabs(ln_abslam));
  411. lnpre_err += 2.0 * GSL_DBL_EPSILON * fabs(lnpre_val);
  412. stat_e = gsl_sf_exp_mult_err_e(lnpre_val + lm, lnpre_err, P.val, P.err, result);
  413. return GSL_ERROR_SELECT_2(stat_e, stat_P);
  414. }
  415. }
  416. else {
  417. /* Backward recurrence.
  418. */
  419. const double coth_eta = 1.0/tanh(eta);
  420. const double coth_err_mult = fabs(eta) + 1.0;
  421. gsl_sf_result rH;
  422. int stat_CF1 = legendre_H3d_CF1_ser(ell, lambda, coth_eta, &rH);
  423. double Hlm1;
  424. double Hl = GSL_SQRT_DBL_MIN;
  425. double Hlp1 = rH.val * Hl;
  426. int lp;
  427. for(lp=ell; lp>0; lp--) {
  428. double root_term_0 = hypot(lambda,lp);
  429. double root_term_1 = hypot(lambda,lp+1.0);
  430. Hlm1 = ((2.0*lp + 1.0)*coth_eta*Hl - root_term_1 * Hlp1)/root_term_0;
  431. Hlp1 = Hl;
  432. Hl = Hlm1;
  433. }
  434. if(fabs(Hl) > fabs(Hlp1)) {
  435. gsl_sf_result H0;
  436. int stat_H0 = gsl_sf_legendre_H3d_0_e(lambda, eta, &H0);
  437. result->val = GSL_SQRT_DBL_MIN/Hl * H0.val;
  438. result->err = GSL_SQRT_DBL_MIN/fabs(Hl) * H0.err;
  439. result->err += fabs(rH.err/rH.val) * (ell+1.0) * coth_err_mult * fabs(result->val);
  440. result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
  441. return GSL_ERROR_SELECT_2(stat_H0, stat_CF1);
  442. }
  443. else {
  444. gsl_sf_result H1;
  445. int stat_H1 = gsl_sf_legendre_H3d_1_e(lambda, eta, &H1);
  446. result->val = GSL_SQRT_DBL_MIN/Hlp1 * H1.val;
  447. result->err = GSL_SQRT_DBL_MIN/fabs(Hlp1) * H1.err;
  448. result->err += fabs(rH.err/rH.val) * (ell+1.0) * coth_err_mult * fabs(result->val);
  449. result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
  450. return GSL_ERROR_SELECT_2(stat_H1, stat_CF1);
  451. }
  452. }
  453. }
  454. int
  455. gsl_sf_legendre_H3d_array(const int lmax, const double lambda, const double eta, double * result_array)
  456. {
  457. /* CHECK_POINTER(result_array) */
  458. if(eta < 0.0 || lmax < 0) {
  459. int ell;
  460. for(ell=0; ell<=lmax; ell++) result_array[ell] = 0.0;
  461. GSL_ERROR ("domain error", GSL_EDOM);
  462. }
  463. else if(eta > GSL_LOG_DBL_MAX) {
  464. /* cosh(eta) is too big. */
  465. int ell;
  466. for(ell=0; ell<=lmax; ell++) result_array[ell] = 0.0;
  467. GSL_ERROR ("overflow", GSL_EOVRFLW);
  468. }
  469. else if(lmax == 0) {
  470. gsl_sf_result H0;
  471. int stat = gsl_sf_legendre_H3d_e(0, lambda, eta, &H0);
  472. result_array[0] = H0.val;
  473. return stat;
  474. }
  475. else {
  476. /* Not the most efficient method. But what the hell... it's simple.
  477. */
  478. gsl_sf_result r_Hlp1;
  479. gsl_sf_result r_Hl;
  480. int stat_lmax = gsl_sf_legendre_H3d_e(lmax, lambda, eta, &r_Hlp1);
  481. int stat_lmaxm1 = gsl_sf_legendre_H3d_e(lmax-1, lambda, eta, &r_Hl);
  482. int stat_max = GSL_ERROR_SELECT_2(stat_lmax, stat_lmaxm1);
  483. const double coth_eta = 1.0/tanh(eta);
  484. int stat_recursion = GSL_SUCCESS;
  485. double Hlp1 = r_Hlp1.val;
  486. double Hl = r_Hl.val;
  487. double Hlm1;
  488. int ell;
  489. result_array[lmax] = Hlp1;
  490. result_array[lmax-1] = Hl;
  491. for(ell=lmax-1; ell>0; ell--) {
  492. double root_term_0 = hypot(lambda,ell);
  493. double root_term_1 = hypot(lambda,ell+1.0);
  494. Hlm1 = ((2.0*ell + 1.0)*coth_eta*Hl - root_term_1 * Hlp1)/root_term_0;
  495. result_array[ell-1] = Hlm1;
  496. if(!(Hlm1 < GSL_DBL_MAX)) stat_recursion = GSL_EOVRFLW;
  497. Hlp1 = Hl;
  498. Hl = Hlm1;
  499. }
  500. return GSL_ERROR_SELECT_2(stat_recursion, stat_max);
  501. }
  502. }
  503. /*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/
  504. #include "gsl_specfunc__eval.h"
  505. double gsl_sf_legendre_H3d_0(const double lambda, const double eta)
  506. {
  507. EVAL_RESULT(gsl_sf_legendre_H3d_0_e(lambda, eta, &result));
  508. }
  509. double gsl_sf_legendre_H3d_1(const double lambda, const double eta)
  510. {
  511. EVAL_RESULT(gsl_sf_legendre_H3d_1_e(lambda, eta, &result));
  512. }
  513. double gsl_sf_legendre_H3d(const int l, const double lambda, const double eta)
  514. {
  515. EVAL_RESULT(gsl_sf_legendre_H3d_e(l, lambda, eta, &result));
  516. }