GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
oct-specfun.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2026 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <cmath>
31
32#include <algorithm>
33#include <limits>
34#include <string>
35
36#include "CColVector.h"
37#include "CMatrix.h"
38#include "CNDArray.h"
39#include "Faddeeva.hh"
40#include "amos-proto.h"
41#include "dMatrix.h"
42#include "dNDArray.h"
43#include "dRowVector.h"
44#include "f77-fcn.h"
45#include "fCColVector.h"
46#include "fCMatrix.h"
47#include "fCNDArray.h"
48#include "fMatrix.h"
49#include "fNDArray.h"
50#include "fRowVector.h"
51#include "lo-ieee.h"
52#include "mappers.h"
53#include "mx-inlines.cc"
54#include "oct-error.h"
55#include "oct-specfun.h"
56#include "slatec-proto.h"
57
60
61static inline Complex
62bessel_return_value (const Complex& val, octave_idx_type ierr)
63{
64 static const Complex inf_val
65 = Complex (numeric_limits<double>::Inf (),
66 numeric_limits<double>::Inf ());
67
68 static const Complex nan_val
69 = Complex (numeric_limits<double>::NaN (),
70 numeric_limits<double>::NaN ());
71
72 Complex retval;
73
74 switch (ierr)
75 {
76 case 0:
77 case 3:
78 case 4:
79 retval = val;
80 break;
81
82 case 2:
83 retval = inf_val;
84 break;
85
86 default:
87 retval = nan_val;
88 break;
89 }
90
91 return retval;
92}
93
94static inline FloatComplex
95bessel_return_value (const FloatComplex& val, octave_idx_type ierr)
96{
97 static const FloatComplex inf_val
98 = FloatComplex (numeric_limits<float>::Inf (),
99 numeric_limits<float>::Inf ());
100
101 static const FloatComplex nan_val
102 = FloatComplex (numeric_limits<float>::NaN (),
103 numeric_limits<float>::NaN ());
104
105 FloatComplex retval;
106
107 switch (ierr)
108 {
109 case 0:
110 case 3:
111 case 4:
112 retval = val;
113 break;
114
115 case 2:
116 retval = inf_val;
117 break;
118
119 default:
120 retval = nan_val;
121 break;
122 }
123
124 return retval;
125}
126
128airy (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr)
129{
130 double ar = 0.0;
131 double ai = 0.0;
132
133 double zr = z.real ();
134 double zi = z.imag ();
135
136 F77_INT id = (deriv ? 1 : 0);
137 F77_INT nz, t_ierr;
138 F77_INT sc = (scaled ? 2 : 1);
139
140 F77_FUNC (zairy, ZAIRY) (zr, zi, id, sc, ar, ai, nz, t_ierr);
141
142 ierr = t_ierr;
143
144 if (zi == 0.0 && (! scaled || zr >= 0.0))
145 ai = 0.0;
146
147 return bessel_return_value (Complex (ar, ai), ierr);
148}
149
151airy (const ComplexMatrix& z, bool deriv, bool scaled,
153{
154 octave_idx_type nr = z.rows ();
155 octave_idx_type nc = z.cols ();
156
157 ComplexMatrix retval (nr, nc);
158
159 ierr.resize (dim_vector (nr, nc));
160
161 for (octave_idx_type j = 0; j < nc; j++)
162 for (octave_idx_type i = 0; i < nr; i++)
163 retval(i, j) = airy (z(i, j), deriv, scaled, ierr(i, j));
164
165 return retval;
166}
167
169airy (const ComplexNDArray& z, bool deriv, bool scaled,
171{
172 const dim_vector& dv = z.dims ();
173 octave_idx_type nel = dv.numel ();
174 ComplexNDArray retval (dv);
175
176 ierr.resize (dv);
177
178 for (octave_idx_type i = 0; i < nel; i++)
179 retval(i) = airy (z(i), deriv, scaled, ierr(i));
180
181 return retval;
182}
183
185airy (const FloatComplex& z, bool deriv, bool scaled,
187{
188 FloatComplex a;
189
190 F77_INT id = (deriv ? 1 : 0);
191 F77_INT nz, t_ierr;
192 F77_INT sc = (scaled ? 2 : 1);
193
194 F77_FUNC (cairy, CAIRY) (F77_CONST_CMPLX_ARG (&z), id, sc,
195 F77_CMPLX_ARG (&a), nz, t_ierr);
196
197 ierr = t_ierr;
198
199 float ar = a.real ();
200 float ai = a.imag ();
201
202 if (z.imag () == 0.0 && (! scaled || z.real () >= 0.0))
203 ai = 0.0;
204
205 return bessel_return_value (FloatComplex (ar, ai), ierr);
206}
207
209airy (const FloatComplexMatrix& z, bool deriv, bool scaled,
211{
212 octave_idx_type nr = z.rows ();
213 octave_idx_type nc = z.cols ();
214
215 FloatComplexMatrix retval (nr, nc);
216
217 ierr.resize (dim_vector (nr, nc));
218
219 for (octave_idx_type j = 0; j < nc; j++)
220 for (octave_idx_type i = 0; i < nr; i++)
221 retval(i, j) = airy (z(i, j), deriv, scaled, ierr(i, j));
222
223 return retval;
224}
225
227airy (const FloatComplexNDArray& z, bool deriv, bool scaled,
229{
230 const dim_vector& dv = z.dims ();
231 octave_idx_type nel = dv.numel ();
232 FloatComplexNDArray retval (dv);
233
234 ierr.resize (dv);
235
236 for (octave_idx_type i = 0; i < nel; i++)
237 retval(i) = airy (z(i), deriv, scaled, ierr(i));
238
239 return retval;
240}
241
242static inline Complex
243zbesj (const Complex& z, double alpha, int kode, octave_idx_type& ierr);
244
245static inline Complex
246zbesy (const Complex& z, double alpha, int kode, octave_idx_type& ierr);
247
248static inline Complex
249zbesi (const Complex& z, double alpha, int kode, octave_idx_type& ierr);
250
251static inline Complex
252zbesk (const Complex& z, double alpha, int kode, octave_idx_type& ierr);
253
254static inline Complex
255zbesh1 (const Complex& z, double alpha, int kode, octave_idx_type& ierr);
256
257static inline Complex
258zbesh2 (const Complex& z, double alpha, int kode, octave_idx_type& ierr);
259
260static inline Complex
261zbesj (const Complex& z, double alpha, int kode, octave_idx_type& ierr)
262{
263 Complex retval;
264
265 if (alpha >= 0.0)
266 {
267 double yr = 0.0;
268 double yi = 0.0;
269
270 F77_INT nz, t_ierr;
271
272 double zr = z.real ();
273 double zi = z.imag ();
274
275 F77_FUNC (zbesj, ZBESJ) (zr, zi, alpha, kode, 1, &yr, &yi, nz, t_ierr);
276
277 ierr = t_ierr;
278
279 if (zi == 0.0 && zr >= 0.0)
280 yi = 0.0;
281
282 retval = bessel_return_value (Complex (yr, yi), ierr);
283 }
284 else if (octave::math::is_integer (alpha))
285 {
286 // zbesy can overflow as z->0, and cause troubles for generic case below
287 alpha = -alpha;
288 Complex tmp = zbesj (z, alpha, kode, ierr);
289 if ((static_cast<long> (alpha)) & 1)
290 tmp = - tmp;
291 retval = bessel_return_value (tmp, ierr);
292 }
293 else
294 {
295 alpha = -alpha;
296
297 Complex tmp = cos (M_PI * alpha) * zbesj (z, alpha, kode, ierr);
298
299 if (ierr == 0 || ierr == 3)
300 {
301 tmp -= sin (M_PI * alpha) * zbesy (z, alpha, kode, ierr);
302
303 retval = bessel_return_value (tmp, ierr);
304 }
305 else
306 retval = Complex (numeric_limits<double>::NaN (),
307 numeric_limits<double>::NaN ());
308 }
309
310 return retval;
311}
312
313static inline Complex
314zbesy (const Complex& z, double alpha, int kode, octave_idx_type& ierr)
315{
316 Complex retval;
317
318 if (alpha >= 0.0)
319 {
320 double yr = 0.0;
321 double yi = 0.0;
322
323 F77_INT nz, t_ierr;
324
325 double wr, wi;
326
327 double zr = z.real ();
328 double zi = z.imag ();
329
330 ierr = 0;
331
332 if (zr == 0.0 && zi == 0.0)
333 {
334 yr = -numeric_limits<double>::Inf ();
335 yi = 0.0;
336 }
337 else
338 {
339 F77_FUNC (zbesy, ZBESY) (zr, zi, alpha, kode, 1, &yr, &yi, nz,
340 &wr, &wi, t_ierr);
341
342 ierr = t_ierr;
343
344 if (zi == 0.0 && zr >= 0.0)
345 yi = 0.0;
346 }
347
348 return bessel_return_value (Complex (yr, yi), ierr);
349 }
350 else if (octave::math::is_integer (alpha - 0.5))
351 {
352 // zbesy can overflow as z->0, and cause troubles for generic case below
353 alpha = -alpha;
354 Complex tmp = zbesj (z, alpha, kode, ierr);
355 if ((static_cast<long> (alpha - 0.5)) & 1)
356 tmp = - tmp;
357 retval = bessel_return_value (tmp, ierr);
358 }
359 else
360 {
361 alpha = -alpha;
362
363 Complex tmp = cos (M_PI * alpha) * zbesy (z, alpha, kode, ierr);
364
365 if (ierr == 0 || ierr == 3)
366 {
367 tmp += sin (M_PI * alpha) * zbesj (z, alpha, kode, ierr);
368
369 retval = bessel_return_value (tmp, ierr);
370 }
371 else
372 retval = Complex (numeric_limits<double>::NaN (),
373 numeric_limits<double>::NaN ());
374 }
375
376 return retval;
377}
378
379static inline Complex
380zbesi (const Complex& z, double alpha, int kode, octave_idx_type& ierr)
381{
382 Complex retval;
383
384 if (alpha >= 0.0)
385 {
386 double yr = 0.0;
387 double yi = 0.0;
388
389 F77_INT nz, t_ierr;
390
391 double zr = z.real ();
392 double zi = z.imag ();
393
394 F77_FUNC (zbesi, ZBESI) (zr, zi, alpha, kode, 1, &yr, &yi, nz, t_ierr);
395
396 ierr = t_ierr;
397
398 if (zi == 0.0 && zr >= 0.0)
399 yi = 0.0;
400
401 retval = bessel_return_value (Complex (yr, yi), ierr);
402 }
403 else if (octave::math::is_integer (alpha))
404 {
405 // zbesi can overflow as z->0, and cause troubles for generic case below
406 alpha = -alpha;
407 Complex tmp = zbesi (z, alpha, kode, ierr);
408 retval = bessel_return_value (tmp, ierr);
409 }
410 else
411 {
412 alpha = -alpha;
413
414 Complex tmp = zbesi (z, alpha, kode, ierr);
415
416 if (ierr == 0 || ierr == 3)
417 {
418 Complex tmp2 = (2.0 / M_PI) * sin (M_PI * alpha)
419 * zbesk (z, alpha, kode, ierr);
420
421 if (kode == 2)
422 {
423 // Compensate for different scaling factor of besk.
424 tmp2 *= exp (-z - std::abs (z.real ()));
425 }
426
427 tmp += tmp2;
428
429 retval = bessel_return_value (tmp, ierr);
430 }
431 else
432 retval = Complex (numeric_limits<double>::NaN (),
433 numeric_limits<double>::NaN ());
434 }
435
436 return retval;
437}
438
439static inline Complex
440zbesk (const Complex& z, double alpha, int kode, octave_idx_type& ierr)
441{
442 Complex retval;
443
444 if (alpha >= 0.0)
445 {
446 double yr = 0.0;
447 double yi = 0.0;
448
449 F77_INT nz, t_ierr;
450
451 double zr = z.real ();
452 double zi = z.imag ();
453
454 ierr = 0;
455
456 if (zr == 0.0 && zi == 0.0)
457 {
458 yr = numeric_limits<double>::Inf ();
459 yi = 0.0;
460 }
461 else
462 {
463 F77_FUNC (zbesk, ZBESK) (zr, zi, alpha, kode, 1, &yr, &yi, nz,
464 t_ierr);
465
466 ierr = t_ierr;
467
468 if (zi == 0.0 && zr >= 0.0)
469 yi = 0.0;
470 }
471
472 retval = bessel_return_value (Complex (yr, yi), ierr);
473 }
474 else
475 {
476 Complex tmp = zbesk (z, -alpha, kode, ierr);
477
478 retval = bessel_return_value (tmp, ierr);
479 }
480
481 return retval;
482}
483
484static inline Complex
485zbesh1 (const Complex& z, double alpha, int kode, octave_idx_type& ierr)
486{
487 Complex retval;
488
489 if (alpha >= 0.0)
490 {
491 double yr = 0.0;
492 double yi = 0.0;
493
494 F77_INT nz, t_ierr;
495
496 double zr = z.real ();
497 double zi = z.imag ();
498
499 F77_FUNC (zbesh, ZBESH) (zr, zi, alpha, kode, 1, 1, &yr, &yi, nz,
500 t_ierr);
501
502 ierr = t_ierr;
503
504 retval = bessel_return_value (Complex (yr, yi), ierr);
505 }
506 else
507 {
508 alpha = -alpha;
509
510 static const Complex eye = Complex (0.0, 1.0);
511
512 Complex tmp = exp (M_PI * alpha * eye) * zbesh1 (z, alpha, kode, ierr);
513
514 retval = bessel_return_value (tmp, ierr);
515 }
516
517 return retval;
518}
519
520static inline Complex
521zbesh2 (const Complex& z, double alpha, int kode, octave_idx_type& ierr)
522{
523 Complex retval;
524
525 if (alpha >= 0.0)
526 {
527 double yr = 0.0;
528 double yi = 0.0;
529
530 F77_INT nz, t_ierr;
531
532 double zr = z.real ();
533 double zi = z.imag ();
534
535 F77_FUNC (zbesh, ZBESH) (zr, zi, alpha, kode, 2, 1, &yr, &yi, nz,
536 t_ierr);
537
538 ierr = t_ierr;
539
540 retval = bessel_return_value (Complex (yr, yi), ierr);
541 }
542 else
543 {
544 alpha = -alpha;
545
546 static const Complex eye = Complex (0.0, 1.0);
547
548 Complex tmp = exp (-M_PI * alpha * eye) * zbesh2 (z, alpha, kode, ierr);
549
550 retval = bessel_return_value (tmp, ierr);
551 }
552
553 return retval;
554}
555
557
558static inline Complex
559do_bessel (dptr f, const char *, double alpha, const Complex& x,
560 bool scaled, octave_idx_type& ierr)
561{
562 Complex retval;
563
564 retval = f (x, alpha, (scaled ? 2 : 1), ierr);
565
566 return retval;
567}
568
569static inline ComplexMatrix
570do_bessel (dptr f, const char *, double alpha, const ComplexMatrix& x,
571 bool scaled, Array<octave_idx_type>& ierr)
572{
573 octave_idx_type nr = x.rows ();
574 octave_idx_type nc = x.cols ();
575
576 ComplexMatrix retval (nr, nc);
577
578 ierr.resize (dim_vector (nr, nc));
579
580 for (octave_idx_type j = 0; j < nc; j++)
581 for (octave_idx_type i = 0; i < nr; i++)
582 retval(i, j) = f (x(i, j), alpha, (scaled ? 2 : 1), ierr(i, j));
583
584 return retval;
585}
586
587static inline ComplexMatrix
588do_bessel (dptr f, const char *, const Matrix& alpha, const Complex& x,
589 bool scaled, Array<octave_idx_type>& ierr)
590{
591 octave_idx_type nr = alpha.rows ();
592 octave_idx_type nc = alpha.cols ();
593
594 ComplexMatrix retval (nr, nc);
595
596 ierr.resize (dim_vector (nr, nc));
597
598 for (octave_idx_type j = 0; j < nc; j++)
599 for (octave_idx_type i = 0; i < nr; i++)
600 retval(i, j) = f (x, alpha(i, j), (scaled ? 2 : 1), ierr(i, j));
601
602 return retval;
603}
604
605static inline ComplexMatrix
606do_bessel (dptr f, const char *fn, const Matrix& alpha,
607 const ComplexMatrix& x, bool scaled, Array<octave_idx_type>& ierr)
608{
609 ComplexMatrix retval;
610
611 octave_idx_type x_nr = x.rows ();
612 octave_idx_type x_nc = x.cols ();
613
614 octave_idx_type alpha_nr = alpha.rows ();
615 octave_idx_type alpha_nc = alpha.cols ();
616
617 if (x_nr != alpha_nr || x_nc != alpha_nc)
618 (*current_liboctave_error_handler)
619 ("%s: the sizes of alpha and x must conform", fn);
620
621 octave_idx_type nr = x_nr;
622 octave_idx_type nc = x_nc;
623
624 retval.resize (nr, nc);
625
626 ierr.resize (dim_vector (nr, nc));
627
628 for (octave_idx_type j = 0; j < nc; j++)
629 for (octave_idx_type i = 0; i < nr; i++)
630 retval(i, j) = f (x(i, j), alpha(i, j), (scaled ? 2 : 1), ierr(i, j));
631
632 return retval;
633}
634
635static inline ComplexNDArray
636do_bessel (dptr f, const char *, double alpha, const ComplexNDArray& x,
637 bool scaled, Array<octave_idx_type>& ierr)
638{
639 const dim_vector& dv = x.dims ();
640 octave_idx_type nel = dv.numel ();
641 ComplexNDArray retval (dv);
642
643 ierr.resize (dv);
644
645 for (octave_idx_type i = 0; i < nel; i++)
646 retval(i) = f (x(i), alpha, (scaled ? 2 : 1), ierr(i));
647
648 return retval;
649}
650
651static inline ComplexNDArray
652do_bessel (dptr f, const char *, const NDArray& alpha, const Complex& x,
653 bool scaled, Array<octave_idx_type>& ierr)
654{
655 const dim_vector& dv = alpha.dims ();
656 octave_idx_type nel = dv.numel ();
657 ComplexNDArray retval (dv);
658
659 ierr.resize (dv);
660
661 for (octave_idx_type i = 0; i < nel; i++)
662 retval(i) = f (x, alpha(i), (scaled ? 2 : 1), ierr(i));
663
664 return retval;
665}
666
667static inline ComplexNDArray
668do_bessel (dptr f, const char *fn, const NDArray& alpha,
669 const ComplexNDArray& x, bool scaled, Array<octave_idx_type>& ierr)
670{
671 const dim_vector& dv = x.dims ();
672 ComplexNDArray retval;
673
674 if (dv != alpha.dims ())
675 (*current_liboctave_error_handler)
676 ("%s: the sizes of alpha and x must conform", fn);
677
678 octave_idx_type nel = dv.numel ();
679
680 retval.resize (dv);
681 ierr.resize (dv);
682
683 for (octave_idx_type i = 0; i < nel; i++)
684 retval(i) = f (x(i), alpha(i), (scaled ? 2 : 1), ierr(i));
685
686 return retval;
687}
688
689static inline ComplexMatrix
690do_bessel (dptr f, const char *, const RowVector& alpha,
691 const ComplexColumnVector& x, bool scaled,
693{
694 octave_idx_type nr = x.numel ();
695 octave_idx_type nc = alpha.numel ();
696
697 ComplexMatrix retval (nr, nc);
698
699 ierr.resize (dim_vector (nr, nc));
700
701 for (octave_idx_type j = 0; j < nc; j++)
702 for (octave_idx_type i = 0; i < nr; i++)
703 retval(i, j) = f (x(i), alpha(j), (scaled ? 2 : 1), ierr(i, j));
704
705 return retval;
706}
707
708#define SS_BESSEL(name, fcn) \
709 Complex \
710 name (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr) \
711 { \
712 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
713 }
714
715#define SM_BESSEL(name, fcn) \
716 ComplexMatrix \
717 name (double alpha, const ComplexMatrix& x, bool scaled, \
718 Array<octave_idx_type>& ierr) \
719 { \
720 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
721 }
722
723#define MS_BESSEL(name, fcn) \
724 ComplexMatrix \
725 name (const Matrix& alpha, const Complex& x, bool scaled, \
726 Array<octave_idx_type>& ierr) \
727 { \
728 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
729 }
730
731#define MM_BESSEL(name, fcn) \
732 ComplexMatrix \
733 name (const Matrix& alpha, const ComplexMatrix& x, bool scaled, \
734 Array<octave_idx_type>& ierr) \
735 { \
736 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
737 }
738
739#define SN_BESSEL(name, fcn) \
740 ComplexNDArray \
741 name (double alpha, const ComplexNDArray& x, bool scaled, \
742 Array<octave_idx_type>& ierr) \
743 { \
744 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
745 }
746
747#define NS_BESSEL(name, fcn) \
748 ComplexNDArray \
749 name (const NDArray& alpha, const Complex& x, bool scaled, \
750 Array<octave_idx_type>& ierr) \
751 { \
752 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
753 }
754
755#define NN_BESSEL(name, fcn) \
756 ComplexNDArray \
757 name (const NDArray& alpha, const ComplexNDArray& x, bool scaled, \
758 Array<octave_idx_type>& ierr) \
759 { \
760 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
761 }
762
763#define RC_BESSEL(name, fcn) \
764 ComplexMatrix \
765 name (const RowVector& alpha, const ComplexColumnVector& x, bool scaled, \
766 Array<octave_idx_type>& ierr) \
767 { \
768 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
769 }
770
771#define ALL_BESSEL(name, fcn) \
772 SS_BESSEL (name, fcn) \
773 SM_BESSEL (name, fcn) \
774 MS_BESSEL (name, fcn) \
775 MM_BESSEL (name, fcn) \
776 SN_BESSEL (name, fcn) \
777 NS_BESSEL (name, fcn) \
778 NN_BESSEL (name, fcn) \
779 RC_BESSEL (name, fcn)
780
787
788#undef ALL_BESSEL
789#undef SS_BESSEL
790#undef SM_BESSEL
791#undef MS_BESSEL
792#undef MM_BESSEL
793#undef SN_BESSEL
794#undef NS_BESSEL
795#undef NN_BESSEL
796#undef RC_BESSEL
797
798static inline FloatComplex
799cbesj (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr);
800
801static inline FloatComplex
802cbesy (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr);
803
804static inline FloatComplex
805cbesi (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr);
806
807static inline FloatComplex
808cbesk (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr);
809
810static inline FloatComplex
811cbesh1 (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr);
812
813static inline FloatComplex
814cbesh2 (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr);
815
816static inline FloatComplex
817cbesj (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr)
818{
819 FloatComplex retval;
820
821 if (alpha >= 0.0)
822 {
823 FloatComplex y = 0.0;
824
825 F77_INT nz, t_ierr;
826
827 F77_FUNC (cbesj, CBESJ) (F77_CONST_CMPLX_ARG (&z), alpha, kode, 1,
828 F77_CMPLX_ARG (&y), nz, t_ierr);
829
830 ierr = t_ierr;
831
832 if (z.imag () == 0.0 && z.real () >= 0.0)
833 y = FloatComplex (y.real (), 0.0);
834
835 retval = bessel_return_value (y, ierr);
836 }
837 else if (octave::math::is_integer (alpha))
838 {
839 // zbesy can overflow as z->0, and cause troubles for generic case below
840 alpha = -alpha;
841 FloatComplex tmp = cbesj (z, alpha, kode, ierr);
842 if ((static_cast<long> (alpha)) & 1)
843 tmp = - tmp;
844 retval = bessel_return_value (tmp, ierr);
845 }
846 else
847 {
848 alpha = -alpha;
849
850 FloatComplex tmp = cosf (static_cast<float> (M_PI) * alpha)
851 * cbesj (z, alpha, kode, ierr);
852
853 if (ierr == 0 || ierr == 3)
854 {
855 tmp -= sinf (static_cast<float> (M_PI) * alpha)
856 * cbesy (z, alpha, kode, ierr);
857
858 retval = bessel_return_value (tmp, ierr);
859 }
860 else
861 retval = FloatComplex (numeric_limits<float>::NaN (),
862 numeric_limits<float>::NaN ());
863 }
864
865 return retval;
866}
867
868static inline FloatComplex
869cbesy (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr)
870{
871 FloatComplex retval;
872
873 if (alpha >= 0.0)
874 {
875 FloatComplex y = 0.0;
876
877 F77_INT nz, t_ierr;
878
880
881 ierr = 0;
882
883 if (z.real () == 0.0 && z.imag () == 0.0)
884 {
885 y = FloatComplex (-numeric_limits<float>::Inf (), 0.0);
886 }
887 else
888 {
889 F77_FUNC (cbesy, CBESY) (F77_CONST_CMPLX_ARG (&z), alpha, kode, 1,
890 F77_CMPLX_ARG (&y), nz,
891 F77_CMPLX_ARG (&w), t_ierr);
892
893 ierr = t_ierr;
894
895 if (z.imag () == 0.0 && z.real () >= 0.0)
896 y = FloatComplex (y.real (), 0.0);
897 }
898
899 return bessel_return_value (y, ierr);
900 }
901 else if (octave::math::is_integer (alpha - 0.5))
902 {
903 // zbesy can overflow as z->0, and cause troubles for generic case below
904 alpha = -alpha;
905 FloatComplex tmp = cbesj (z, alpha, kode, ierr);
906 if ((static_cast<long> (alpha - 0.5)) & 1)
907 tmp = - tmp;
908 retval = bessel_return_value (tmp, ierr);
909 }
910 else
911 {
912 alpha = -alpha;
913
914 FloatComplex tmp = cosf (static_cast<float> (M_PI) * alpha)
915 * cbesy (z, alpha, kode, ierr);
916
917 if (ierr == 0 || ierr == 3)
918 {
919 tmp += sinf (static_cast<float> (M_PI) * alpha)
920 * cbesj (z, alpha, kode, ierr);
921
922 retval = bessel_return_value (tmp, ierr);
923 }
924 else
925 retval = FloatComplex (numeric_limits<float>::NaN (),
926 numeric_limits<float>::NaN ());
927 }
928
929 return retval;
930}
931
932static inline FloatComplex
933cbesi (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr)
934{
935 FloatComplex retval;
936
937 if (alpha >= 0.0)
938 {
939 FloatComplex y = 0.0;
940
941 F77_INT nz, t_ierr;
942
943 F77_FUNC (cbesi, CBESI) (F77_CONST_CMPLX_ARG (&z), alpha, kode, 1,
944 F77_CMPLX_ARG (&y), nz, t_ierr);
945
946 ierr = t_ierr;
947
948 if (z.imag () == 0.0 && z.real () >= 0.0)
949 y = FloatComplex (y.real (), 0.0);
950
951 retval = bessel_return_value (y, ierr);
952 }
953 else
954 {
955 alpha = -alpha;
956
957 FloatComplex tmp = cbesi (z, alpha, kode, ierr);
958
959 if (ierr == 0 || ierr == 3)
960 {
961 FloatComplex tmp2 = static_cast<float> (2.0 / M_PI)
962 * sinf (static_cast<float> (M_PI) * alpha)
963 * cbesk (z, alpha, kode, ierr);
964
965 if (kode == 2)
966 {
967 // Compensate for different scaling factor of besk.
968 tmp2 *= exp (-z - std::abs (z.real ()));
969 }
970
971 tmp += tmp2;
972
973 retval = bessel_return_value (tmp, ierr);
974 }
975 else
976 retval = FloatComplex (numeric_limits<float>::NaN (),
977 numeric_limits<float>::NaN ());
978 }
979
980 return retval;
981}
982
983static inline FloatComplex
984cbesk (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr)
985{
986 FloatComplex retval;
987
988 if (alpha >= 0.0)
989 {
990 FloatComplex y = 0.0;
991
992 F77_INT nz, t_ierr;
993
994 ierr = 0;
995
996 if (z.real () == 0.0 && z.imag () == 0.0)
997 {
998 y = FloatComplex (numeric_limits<float>::Inf (), 0.0);
999 }
1000 else
1001 {
1002 F77_FUNC (cbesk, CBESK) (F77_CONST_CMPLX_ARG (&z), alpha, kode, 1,
1003 F77_CMPLX_ARG (&y), nz, t_ierr);
1004
1005 ierr = t_ierr;
1006
1007 if (z.imag () == 0.0 && z.real () >= 0.0)
1008 y = FloatComplex (y.real (), 0.0);
1009 }
1010
1011 retval = bessel_return_value (y, ierr);
1012 }
1013 else
1014 {
1015 FloatComplex tmp = cbesk (z, -alpha, kode, ierr);
1016
1017 retval = bessel_return_value (tmp, ierr);
1018 }
1019
1020 return retval;
1021}
1022
1023static inline FloatComplex
1024cbesh1 (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr)
1025{
1026 FloatComplex retval;
1027
1028 if (alpha >= 0.0)
1029 {
1030 FloatComplex y = 0.0;
1031
1032 F77_INT nz, t_ierr;
1033
1034 F77_FUNC (cbesh, CBESH) (F77_CONST_CMPLX_ARG (&z), alpha, kode, 1, 1,
1035 F77_CMPLX_ARG (&y), nz, t_ierr);
1036
1037 ierr = t_ierr;
1038
1039 retval = bessel_return_value (y, ierr);
1040 }
1041 else
1042 {
1043 alpha = -alpha;
1044
1045 static const FloatComplex eye = FloatComplex (0.0, 1.0);
1046
1047 FloatComplex tmp = exp (static_cast<float> (M_PI) * alpha * eye)
1048 * cbesh1 (z, alpha, kode, ierr);
1049
1050 retval = bessel_return_value (tmp, ierr);
1051 }
1052
1053 return retval;
1054}
1055
1056static inline FloatComplex
1057cbesh2 (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr)
1058{
1059 FloatComplex retval;
1060
1061 if (alpha >= 0.0)
1062 {
1063 FloatComplex y = 0.0;
1064
1065 F77_INT nz, t_ierr;
1066
1067 F77_FUNC (cbesh, CBESH) (F77_CONST_CMPLX_ARG (&z), alpha, kode, 2, 1,
1068 F77_CMPLX_ARG (&y), nz, t_ierr);
1069
1070 ierr = t_ierr;
1071
1072 retval = bessel_return_value (y, ierr);
1073 }
1074 else
1075 {
1076 alpha = -alpha;
1077
1078 static const FloatComplex eye = FloatComplex (0.0, 1.0);
1079
1080 FloatComplex tmp = exp (-static_cast<float> (M_PI) * alpha * eye)
1081 * cbesh2 (z, alpha, kode, ierr);
1082
1083 retval = bessel_return_value (tmp, ierr);
1084 }
1085
1086 return retval;
1087}
1088
1091
1092static inline FloatComplex
1093do_bessel (fptr f, const char *, float alpha, const FloatComplex& x,
1094 bool scaled, octave_idx_type& ierr)
1095{
1096 FloatComplex retval;
1097
1098 retval = f (x, alpha, (scaled ? 2 : 1), ierr);
1099
1100 return retval;
1101}
1102
1103static inline FloatComplexMatrix
1104do_bessel (fptr f, const char *, float alpha, const FloatComplexMatrix& x,
1105 bool scaled, Array<octave_idx_type>& ierr)
1106{
1107 octave_idx_type nr = x.rows ();
1108 octave_idx_type nc = x.cols ();
1109
1110 FloatComplexMatrix retval (nr, nc);
1111
1112 ierr.resize (dim_vector (nr, nc));
1113
1114 for (octave_idx_type j = 0; j < nc; j++)
1115 for (octave_idx_type i = 0; i < nr; i++)
1116 retval(i, j) = f (x(i, j), alpha, (scaled ? 2 : 1), ierr(i, j));
1117
1118 return retval;
1119}
1120
1121static inline FloatComplexMatrix
1122do_bessel (fptr f, const char *, const FloatMatrix& alpha,
1123 const FloatComplex& x,
1124 bool scaled, Array<octave_idx_type>& ierr)
1125{
1126 octave_idx_type nr = alpha.rows ();
1127 octave_idx_type nc = alpha.cols ();
1128
1129 FloatComplexMatrix retval (nr, nc);
1130
1131 ierr.resize (dim_vector (nr, nc));
1132
1133 for (octave_idx_type j = 0; j < nc; j++)
1134 for (octave_idx_type i = 0; i < nr; i++)
1135 retval(i, j) = f (x, alpha(i, j), (scaled ? 2 : 1), ierr(i, j));
1136
1137 return retval;
1138}
1139
1140static inline FloatComplexMatrix
1141do_bessel (fptr f, const char *fn, const FloatMatrix& alpha,
1142 const FloatComplexMatrix& x, bool scaled,
1144{
1145 FloatComplexMatrix retval;
1146
1147 octave_idx_type x_nr = x.rows ();
1148 octave_idx_type x_nc = x.cols ();
1149
1150 octave_idx_type alpha_nr = alpha.rows ();
1151 octave_idx_type alpha_nc = alpha.cols ();
1152
1153 if (x_nr != alpha_nr || x_nc != alpha_nc)
1154 (*current_liboctave_error_handler)
1155 ("%s: the sizes of alpha and x must conform", fn);
1156
1157 octave_idx_type nr = x_nr;
1158 octave_idx_type nc = x_nc;
1159
1160 retval.resize (nr, nc);
1161
1162 ierr.resize (dim_vector (nr, nc));
1163
1164 for (octave_idx_type j = 0; j < nc; j++)
1165 for (octave_idx_type i = 0; i < nr; i++)
1166 retval(i, j) = f (x(i, j), alpha(i, j), (scaled ? 2 : 1), ierr(i, j));
1167
1168 return retval;
1169}
1170
1171static inline FloatComplexNDArray
1172do_bessel (fptr f, const char *, float alpha, const FloatComplexNDArray& x,
1173 bool scaled, Array<octave_idx_type>& ierr)
1174{
1175 const dim_vector& dv = x.dims ();
1176 octave_idx_type nel = dv.numel ();
1177 FloatComplexNDArray retval (dv);
1178
1179 ierr.resize (dv);
1180
1181 for (octave_idx_type i = 0; i < nel; i++)
1182 retval(i) = f (x(i), alpha, (scaled ? 2 : 1), ierr(i));
1183
1184 return retval;
1185}
1186
1187static inline FloatComplexNDArray
1188do_bessel (fptr f, const char *, const FloatNDArray& alpha,
1189 const FloatComplex& x, bool scaled, Array<octave_idx_type>& ierr)
1190{
1191 const dim_vector& dv = alpha.dims ();
1192 octave_idx_type nel = dv.numel ();
1193 FloatComplexNDArray retval (dv);
1194
1195 ierr.resize (dv);
1196
1197 for (octave_idx_type i = 0; i < nel; i++)
1198 retval(i) = f (x, alpha(i), (scaled ? 2 : 1), ierr(i));
1199
1200 return retval;
1201}
1202
1203static inline FloatComplexNDArray
1204do_bessel (fptr f, const char *fn, const FloatNDArray& alpha,
1205 const FloatComplexNDArray& x, bool scaled,
1207{
1208 const dim_vector& dv = x.dims ();
1209 FloatComplexNDArray retval;
1210
1211 if (dv != alpha.dims ())
1212 (*current_liboctave_error_handler)
1213 ("%s: the sizes of alpha and x must conform", fn);
1214
1215 octave_idx_type nel = dv.numel ();
1216
1217 retval.resize (dv);
1218 ierr.resize (dv);
1219
1220 for (octave_idx_type i = 0; i < nel; i++)
1221 retval(i) = f (x(i), alpha(i), (scaled ? 2 : 1), ierr(i));
1222
1223 return retval;
1224}
1225
1226static inline FloatComplexMatrix
1227do_bessel (fptr f, const char *, const FloatRowVector& alpha,
1228 const FloatComplexColumnVector& x, bool scaled,
1230{
1231 octave_idx_type nr = x.numel ();
1232 octave_idx_type nc = alpha.numel ();
1233
1234 FloatComplexMatrix retval (nr, nc);
1235
1236 ierr.resize (dim_vector (nr, nc));
1237
1238 for (octave_idx_type j = 0; j < nc; j++)
1239 for (octave_idx_type i = 0; i < nr; i++)
1240 retval(i, j) = f (x(i), alpha(j), (scaled ? 2 : 1), ierr(i, j));
1241
1242 return retval;
1243}
1244
1245#define SS_BESSEL(name, fcn) \
1246 FloatComplex \
1247 name (float alpha, const FloatComplex& x, bool scaled, \
1248 octave_idx_type& ierr) \
1249 { \
1250 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1251 }
1252
1253#define SM_BESSEL(name, fcn) \
1254 FloatComplexMatrix \
1255 name (float alpha, const FloatComplexMatrix& x, bool scaled, \
1256 Array<octave_idx_type>& ierr) \
1257 { \
1258 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1259 }
1260
1261#define MS_BESSEL(name, fcn) \
1262 FloatComplexMatrix \
1263 name (const FloatMatrix& alpha, const FloatComplex& x, bool scaled, \
1264 Array<octave_idx_type>& ierr) \
1265 { \
1266 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1267 }
1268
1269#define MM_BESSEL(name, fcn) \
1270 FloatComplexMatrix \
1271 name (const FloatMatrix& alpha, const FloatComplexMatrix& x, \
1272 bool scaled, Array<octave_idx_type>& ierr) \
1273 { \
1274 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1275 }
1276
1277#define SN_BESSEL(name, fcn) \
1278 FloatComplexNDArray \
1279 name (float alpha, const FloatComplexNDArray& x, bool scaled, \
1280 Array<octave_idx_type>& ierr) \
1281 { \
1282 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1283 }
1284
1285#define NS_BESSEL(name, fcn) \
1286 FloatComplexNDArray \
1287 name (const FloatNDArray& alpha, const FloatComplex& x, \
1288 bool scaled, Array<octave_idx_type>& ierr) \
1289 { \
1290 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1291 }
1292
1293#define NN_BESSEL(name, fcn) \
1294 FloatComplexNDArray \
1295 name (const FloatNDArray& alpha, const FloatComplexNDArray& x, \
1296 bool scaled, Array<octave_idx_type>& ierr) \
1297 { \
1298 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1299 }
1300
1301#define RC_BESSEL(name, fcn) \
1302 FloatComplexMatrix \
1303 name (const FloatRowVector& alpha, \
1304 const FloatComplexColumnVector& x, bool scaled, \
1305 Array<octave_idx_type>& ierr) \
1306 { \
1307 return do_bessel (fcn, #name, alpha, x, scaled, ierr); \
1308 }
1309
1310#define ALL_BESSEL(name, fcn) \
1311 SS_BESSEL (name, fcn) \
1312 SM_BESSEL (name, fcn) \
1313 MS_BESSEL (name, fcn) \
1314 MM_BESSEL (name, fcn) \
1315 SN_BESSEL (name, fcn) \
1316 NS_BESSEL (name, fcn) \
1317 NN_BESSEL (name, fcn) \
1318 RC_BESSEL (name, fcn)
1319
1326
1327#undef ALL_BESSEL
1328#undef SS_BESSEL
1329#undef SM_BESSEL
1330#undef MS_BESSEL
1331#undef MM_BESSEL
1332#undef SN_BESSEL
1333#undef NS_BESSEL
1334#undef NN_BESSEL
1335#undef RC_BESSEL
1336
1337Complex
1338biry (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr)
1339{
1340 double ar = 0.0;
1341 double ai = 0.0;
1342
1343 double zr = z.real ();
1344 double zi = z.imag ();
1345
1346 F77_INT id = (deriv ? 1 : 0);
1347 F77_INT t_ierr;
1348 F77_INT sc = (scaled ? 2 : 1);
1349
1350 F77_FUNC (zbiry, ZBIRY) (zr, zi, id, sc, ar, ai, t_ierr);
1351
1352 ierr = t_ierr;
1353
1354 if (zi == 0.0 && (! scaled || zr >= 0.0))
1355 ai = 0.0;
1356
1357 return bessel_return_value (Complex (ar, ai), ierr);
1358}
1359
1361biry (const ComplexMatrix& z, bool deriv, bool scaled,
1363{
1364 octave_idx_type nr = z.rows ();
1365 octave_idx_type nc = z.cols ();
1366
1367 ComplexMatrix retval (nr, nc);
1368
1369 ierr.resize (dim_vector (nr, nc));
1370
1371 for (octave_idx_type j = 0; j < nc; j++)
1372 for (octave_idx_type i = 0; i < nr; i++)
1373 retval(i, j) = biry (z(i, j), deriv, scaled, ierr(i, j));
1374
1375 return retval;
1376}
1377
1379biry (const ComplexNDArray& z, bool deriv, bool scaled,
1381{
1382 const dim_vector& dv = z.dims ();
1383 octave_idx_type nel = dv.numel ();
1384 ComplexNDArray retval (dv);
1385
1386 ierr.resize (dv);
1387
1388 for (octave_idx_type i = 0; i < nel; i++)
1389 retval(i) = biry (z(i), deriv, scaled, ierr(i));
1390
1391 return retval;
1392}
1393
1395biry (const FloatComplex& z, bool deriv, bool scaled,
1397{
1398 FloatComplex a;
1399
1400 F77_INT id = (deriv ? 1 : 0);
1401 F77_INT t_ierr;
1402 F77_INT sc = (scaled ? 2 : 1);
1403
1404 F77_FUNC (cbiry, CBIRY) (F77_CONST_CMPLX_ARG (&z), id, sc,
1405 F77_CMPLX_ARG (&a), t_ierr);
1406
1407 ierr = t_ierr;
1408
1409 float ar = a.real ();
1410 float ai = a.imag ();
1411
1412 if (z.imag () == 0.0 && (! scaled || z.real () >= 0.0))
1413 ai = 0.0;
1414
1415 return bessel_return_value (FloatComplex (ar, ai), ierr);
1416}
1417
1419biry (const FloatComplexMatrix& z, bool deriv, bool scaled,
1421{
1422 octave_idx_type nr = z.rows ();
1423 octave_idx_type nc = z.cols ();
1424
1425 FloatComplexMatrix retval (nr, nc);
1426
1427 ierr.resize (dim_vector (nr, nc));
1428
1429 for (octave_idx_type j = 0; j < nc; j++)
1430 for (octave_idx_type i = 0; i < nr; i++)
1431 retval(i, j) = biry (z(i, j), deriv, scaled, ierr(i, j));
1432
1433 return retval;
1434}
1435
1437biry (const FloatComplexNDArray& z, bool deriv, bool scaled,
1439{
1440 const dim_vector& dv = z.dims ();
1441 octave_idx_type nel = dv.numel ();
1442 FloatComplexNDArray retval (dv);
1443
1444 ierr.resize (dv);
1445
1446 for (octave_idx_type i = 0; i < nel; i++)
1447 retval(i) = biry (z(i), deriv, scaled, ierr(i));
1448
1449 return retval;
1450}
1451
1452// Real and complex Dawson function (= scaled erfi) from Faddeeva package
1453double
1454dawson (double x) { return Faddeeva::Dawson (x); }
1455float
1456dawson (float x) { return Faddeeva::Dawson (x); }
1457
1458Complex
1460{
1461 return Faddeeva::Dawson (x);
1462}
1463
1466{
1467 Complex xd (x.real (), x.imag ());
1468 Complex ret;
1469 ret = Faddeeva::Dawson (xd, std::numeric_limits<float>::epsilon ());
1470 return FloatComplex (ret.real (), ret.imag ());
1471}
1472
1473void
1474ellipj (double u, double m, double& sn, double& cn, double& dn, double& err)
1475{
1476 static const int Nmax = 16;
1477 double m1, t=0, si_u, co_u, se_u, ta_u, b, c[Nmax], a[Nmax], phi;
1478 int n, Nn, ii;
1479
1480 if (m < 0 || m > 1)
1481 {
1482 (*current_liboctave_warning_with_id_handler)
1483 ("Octave:ellipj-invalid-m",
1484 "ellipj: invalid M value, required value 0 <= M <= 1");
1485
1486 sn = cn = dn = lo_ieee_nan_value ();
1487
1488 return;
1489 }
1490
1491 double sqrt_eps = std::sqrt (std::numeric_limits<double>::epsilon ());
1492 if (m < sqrt_eps)
1493 {
1494 // For small m, (Abramowitz and Stegun, Section 16.13)
1495 si_u = sin (u);
1496 co_u = cos (u);
1497 t = 0.25*m*(u - si_u*co_u);
1498 sn = si_u - t * co_u;
1499 cn = co_u + t * si_u;
1500 dn = 1 - 0.5*m*si_u*si_u;
1501 }
1502 else if ((1 - m) < sqrt_eps)
1503 {
1504 // For m1 = (1-m) small (Abramowitz and Stegun, Section 16.15)
1505 m1 = 1 - m;
1506 si_u = sinh (u);
1507 co_u = cosh (u);
1508 ta_u = tanh (u);
1509 se_u = 1/co_u;
1510 sn = ta_u + 0.25*m1*(si_u*co_u - u)*se_u*se_u;
1511 cn = se_u - 0.25*m1*(si_u*co_u - u)*ta_u*se_u;
1512 dn = se_u + 0.25*m1*(si_u*co_u + u)*ta_u*se_u;
1513 }
1514 else
1515 {
1516 // Arithmetic-Geometric Mean (AGM) algorithm
1517 // (Abramowitz and Stegun, Section 16.4)
1518 a[0] = 1;
1519 b = std::sqrt (1 - m);
1520 c[0] = std::sqrt (m);
1521 for (n = 1; n < Nmax; ++n)
1522 {
1523 a[n] = (a[n - 1] + b)/2;
1524 c[n] = (a[n - 1] - b)/2;
1525 b = std::sqrt (a[n - 1]*b);
1526 if (c[n]/a[n] < std::numeric_limits<double>::epsilon ()) break;
1527 }
1528 if (n >= Nmax - 1)
1529 {
1530 err = 1;
1531 return;
1532 }
1533 Nn = n;
1534 for (ii = 1; n > 0; ii *= 2, --n) {} // ii = pow(2,Nn)
1535 phi = ii*a[Nn]*u;
1536 for (n = Nn; n > 0; --n)
1537 {
1538 phi = (std::asin ((c[n]/a[n])* sin (phi)) + phi)/2;
1539 }
1540 sn = sin (phi);
1541 cn = cos (phi);
1542 dn = std::sqrt (1 - m*sn*sn);
1543 }
1544}
1545
1546void
1547ellipj (const Complex& u, double m, Complex& sn, Complex& cn, Complex& dn,
1548 double& err)
1549{
1550 double m1 = 1 - m, ss1, cc1, dd1;
1551
1552 ellipj (u.imag (), m1, ss1, cc1, dd1, err);
1553 if (u.real () == 0)
1554 {
1555 // u is pure imag: Jacoby imag. transf.
1556 sn = Complex (0, ss1/cc1);
1557 cn = 1/cc1; // cn.imag = 0;
1558 dn = dd1/cc1; // dn.imag = 0;
1559 }
1560 else
1561 {
1562 // u is generic complex
1563 double ss, cc, dd, ddd;
1564
1565 ellipj (u.real (), m, ss, cc, dd, err);
1566 ddd = cc1*cc1 + m*ss*ss*ss1*ss1;
1567 sn = Complex (ss*dd1/ddd, cc*dd*ss1*cc1/ddd);
1568 cn = Complex (cc*cc1/ddd, -ss*dd*ss1*dd1/ddd);
1569 dn = Complex (dd*cc1*dd1/ddd, -m*ss*cc*ss1/ddd);
1570 }
1571}
1572
1573// Complex error function from the Faddeeva package
1574Complex
1575erf (const Complex& x)
1576{
1577 return Faddeeva::erf (x);
1578}
1579
1582{
1583 Complex xd (x.real (), x.imag ());
1584 Complex ret = Faddeeva::erf (xd, std::numeric_limits<float>::epsilon ());
1585 return FloatComplex (ret.real (), ret.imag ());
1586}
1587
1588// Complex complementary error function from the Faddeeva package
1589Complex
1591{
1592 return Faddeeva::erfc (x);
1593}
1594
1597{
1598 Complex xd (x.real (), x.imag ());
1599 Complex ret = Faddeeva::erfc (xd, std::numeric_limits<float>::epsilon ());
1600 return FloatComplex (ret.real (), ret.imag ());
1601}
1602
1603// The algorithm for erfcinv is an adaptation of the erfinv algorithm
1604// above from P. J. Acklam. It has been modified to run over the
1605// different input domain of erfcinv. See the notes for erfinv for an
1606// explanation.
1607
1608static double
1609do_erfcinv (double x, bool refine)
1610{
1611 // Coefficients of rational approximation.
1612 static const double a[] =
1613 {
1614 -2.806989788730439e+01, 1.562324844726888e+02,
1615 -1.951109208597547e+02, 9.783370457507161e+01,
1616 -2.168328665628878e+01, 1.772453852905383e+00
1617 };
1618 static const double b[] =
1619 {
1620 -5.447609879822406e+01, 1.615858368580409e+02,
1621 -1.556989798598866e+02, 6.680131188771972e+01,
1622 -1.328068155288572e+01
1623 };
1624 static const double c[] =
1625 {
1626 -5.504751339936943e-03, -2.279687217114118e-01,
1627 -1.697592457770869e+00, -1.802933168781950e+00,
1628 3.093354679843505e+00, 2.077595676404383e+00
1629 };
1630 static const double d[] =
1631 {
1632 7.784695709041462e-03, 3.224671290700398e-01,
1633 2.445134137142996e+00, 3.754408661907416e+00
1634 };
1635
1636 static const double spi2 = 8.862269254527579e-01; // sqrt(pi)/2.
1637 static const double pbreak_lo = 0.04850; // 1-pbreak
1638 static const double pbreak_hi = 1.95150; // 1+pbreak
1639 double y;
1640
1641 // Select case.
1642 if (x >= pbreak_lo && x <= pbreak_hi)
1643 {
1644 // Middle region.
1645 const double q = 0.5*(1-x), r = q*q;
1646 const double yn = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q;
1647 const double yd = ((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0;
1648 y = yn / yd;
1649 }
1650 else if (x > 0.0 && x < 2.0)
1651 {
1652 // Tail region.
1653 const double q = (x < 1
1654 ? std::sqrt (-2*std::log (0.5*x))
1655 : std::sqrt (-2*std::log (0.5*(2-x))));
1656
1657 const double yn = ((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5];
1658
1659 const double yd = (((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0;
1660
1661 y = yn / yd;
1662
1663 if (x < pbreak_lo)
1664 y = -y;
1665 }
1666 else if (x == 0.0)
1667 return numeric_limits<double>::Inf ();
1668 else if (x == 2.0)
1669 return -numeric_limits<double>::Inf ();
1670 else
1671 return numeric_limits<double>::NaN ();
1672
1673 if (refine)
1674 {
1675 // One iteration of Halley's method gives full precision.
1676 double u = (erf (y) - (1-x)) * spi2 * exp (y*y);
1677 y -= u / (1 + y*u);
1678 }
1679
1680 return y;
1681}
1682
1683double
1684erfcinv (double x)
1685{
1686 return do_erfcinv (x, true);
1687}
1688
1689float
1690erfcinv (float x)
1691{
1692 return do_erfcinv (x, false);
1693}
1694
1695// Real and complex scaled complementary error function from Faddeeva pkg.
1696double
1697erfcx (double x) { return Faddeeva::erfcx (x); }
1698float
1699erfcx (float x) { return Faddeeva::erfcx (x); }
1700
1701Complex
1703{
1704 return Faddeeva::erfcx (x);
1705}
1706
1709{
1710 Complex xd (x.real (), x.imag ());
1711 Complex ret;
1712 ret = Faddeeva::erfcx (xd, std::numeric_limits<float>::epsilon ());
1713 return FloatComplex (ret.real (), ret.imag ());
1714}
1715
1716// Real and complex imaginary error function from Faddeeva package
1717double
1718erfi (double x) { return Faddeeva::erfi (x); }
1719float
1720erfi (float x) { return Faddeeva::erfi (x); }
1721
1722Complex
1724{
1725 return Faddeeva::erfi (x);
1726}
1727
1730{
1731 Complex xd (x.real (), x.imag ());
1732 Complex ret = Faddeeva::erfi (xd, std::numeric_limits<float>::epsilon ());
1733 return FloatComplex (ret.real (), ret.imag ());
1734}
1735
1736// This algorithm is due to P. J. Acklam.
1737//
1738// See http://home.online.no/~pjacklam/notes/invnorm/
1739//
1740// The rational approximation has relative accuracy 1.15e-9 in the whole
1741// region. For doubles, it is refined by a single step of Halley's 3rd
1742// order method. For single precision, the accuracy is already OK, so
1743// we skip it to get faster evaluation.
1744
1745static double
1746do_erfinv (double x, bool refine)
1747{
1748 // Coefficients of rational approximation.
1749 static const double a[] =
1750 {
1751 -2.806989788730439e+01, 1.562324844726888e+02,
1752 -1.951109208597547e+02, 9.783370457507161e+01,
1753 -2.168328665628878e+01, 1.772453852905383e+00
1754 };
1755 static const double b[] =
1756 {
1757 -5.447609879822406e+01, 1.615858368580409e+02,
1758 -1.556989798598866e+02, 6.680131188771972e+01,
1759 -1.328068155288572e+01
1760 };
1761 static const double c[] =
1762 {
1763 -5.504751339936943e-03, -2.279687217114118e-01,
1764 -1.697592457770869e+00, -1.802933168781950e+00,
1765 3.093354679843505e+00, 2.077595676404383e+00
1766 };
1767 static const double d[] =
1768 {
1769 7.784695709041462e-03, 3.224671290700398e-01,
1770 2.445134137142996e+00, 3.754408661907416e+00
1771 };
1772
1773 static const double spi2 = 8.862269254527579e-01; // sqrt(pi)/2.
1774 static const double pbreak = 0.95150;
1775 double ax = fabs (x), y;
1776
1777 // Select case.
1778 if (ax <= pbreak)
1779 {
1780 // Middle region.
1781 const double q = 0.5 * x, r = q*q;
1782 const double yn = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q;
1783 const double yd = ((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0;
1784 y = yn / yd;
1785 }
1786 else if (ax < 1.0)
1787 {
1788 // Tail region.
1789 const double q = std::sqrt (-2*std::log (0.5*(1-ax)));
1790 const double yn = ((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5];
1791 const double yd = (((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0;
1792 y = yn / yd * math::signum (-x);
1793 }
1794 else if (ax == 1.0)
1795 return numeric_limits<double>::Inf () * math::signum (x);
1796 else
1797 return numeric_limits<double>::NaN ();
1798
1799 if (refine)
1800 {
1801 // One iteration of Halley's method gives full precision.
1802 double u = (erf (y) - x) * spi2 * exp (y*y);
1803 y -= u / (1 + y*u);
1804 }
1805
1806 return y;
1807}
1808
1809double
1810erfinv (double x)
1811{
1812 return do_erfinv (x, true);
1813}
1814
1815float
1816erfinv (float x)
1817{
1818 return do_erfinv (x, false);
1819}
1820
1821Complex
1823{
1824 Complex retval;
1825
1826 if (std::abs (x) < 1)
1827 {
1828 double im = x.imag ();
1829 double u = expm1 (x.real ());
1830 double v = sin (im/2);
1831 v = -2*v*v;
1832 retval = Complex (u*v + u + v, (u+1) * sin (im));
1833 }
1834 else
1835 retval = std::exp (x) - Complex (1);
1836
1837 return retval;
1838}
1839
1842{
1843 FloatComplex retval;
1844
1845 if (std::abs (x) < 1)
1846 {
1847 float im = x.imag ();
1848 float u = expm1 (x.real ());
1849 float v = sin (im/2);
1850 v = -2*v*v;
1851 retval = FloatComplex (u*v + u + v, (u+1) * sin (im));
1852 }
1853 else
1854 retval = std::exp (x) - FloatComplex (1);
1855
1856 return retval;
1857}
1858
1859double
1860gamma (double x)
1861{
1862 double result;
1863
1864 // Special cases for (near) compatibility with Matlab instead of tgamma.
1865 // Matlab does not have -0.
1866
1867 if (x == 0)
1868 result = (math::negative_sign (x)
1869 ? -numeric_limits<double>::Inf ()
1870 : numeric_limits<double>::Inf ());
1871 else if ((x < 0 && math::is_integer (x))
1872 || math::isinf (x))
1873 result = numeric_limits<double>::Inf ();
1874 else if (math::isnan (x))
1875 result = numeric_limits<double>::NaN ();
1876 else
1877 result = std::tgamma (x);
1878
1879 return result;
1880}
1881
1882float
1883gamma (float x)
1884{
1885 float result;
1886
1887 // Special cases for (near) compatibility with Matlab instead of tgamma.
1888 // Matlab does not have -0.
1889
1890 if (x == 0)
1891 result = (math::negative_sign (x)
1892 ? -numeric_limits<float>::Inf ()
1893 : numeric_limits<float>::Inf ());
1894 else if ((x < 0 && math::is_integer (x))
1895 || math::isinf (x))
1896 result = numeric_limits<float>::Inf ();
1897 else if (math::isnan (x))
1898 result = numeric_limits<float>::NaN ();
1899 else
1900 result = std::tgammaf (x);
1901
1902 return result;
1903}
1904
1905Complex
1907{
1908 Complex retval;
1909
1910 double r = x.real (), i = x.imag ();
1911
1912 if (fabs (r) < 0.5 && fabs (i) < 0.5)
1913 {
1914 double u = 2*r + r*r + i*i;
1915 retval = Complex (log1p (u / (1+std::sqrt (u+1))),
1916 atan2 (i, 1 + r));
1917 }
1918 else
1919 retval = std::log (Complex (1) + x);
1920
1921 return retval;
1922}
1923
1926{
1927 FloatComplex retval;
1928
1929 float r = x.real (), i = x.imag ();
1930
1931 if (fabs (r) < 0.5 && fabs (i) < 0.5)
1932 {
1933 float u = 2*r + r*r + i*i;
1934 retval = FloatComplex (log1p (u / (1+std::sqrt (u+1))),
1935 atan2 (i, 1 + r));
1936 }
1937 else
1938 retval = std::log (FloatComplex (1) + x);
1939
1940 return retval;
1941}
1942
1943static const double pi = 3.14159265358979323846;
1944
1945template <typename T>
1946static inline T
1947xlog (const T& x)
1948{
1949 return log (x);
1950}
1951
1952template <>
1953inline double
1954xlog (const double& x)
1955{
1956 return std::log (x);
1957}
1958
1959template <>
1960inline float
1961xlog (const float& x)
1962{
1963 return std::log (x);
1964}
1965
1966template <typename T>
1967static T
1968lanczos_approximation_psi (const T zc)
1969{
1970 // Coefficients for C.Lanczos expansion of psi function from XLiFE++
1971 // gammaFunctions psi_coef[k] = - (2k+1) * lg_coef[k] (see melina++
1972 // gamma functions -1/12, 3/360,-5/1260, 7/1680,-9/1188,
1973 // 11*691/360360,-13/156, 15*3617/122400, ? , ?
1974 static const T dg_coeff[10] =
1975 {
1976 -0.83333333333333333e-1, 0.83333333333333333e-2,
1977 -0.39682539682539683e-2, 0.41666666666666667e-2,
1978 -0.75757575757575758e-2, 0.21092796092796093e-1,
1979 -0.83333333333333333e-1, 0.4432598039215686,
1980 -0.3053954330270122e+1, 0.125318899521531e+2
1981 };
1982
1983 T overz2 = T (1.0) / (zc * zc);
1984 T overz2k = overz2;
1985
1986 T p = 0;
1987 for (octave_idx_type k = 0; k < 10; k++, overz2k *= overz2)
1988 p += dg_coeff[k] * overz2k;
1989 p += xlog (zc) - T (0.5) / zc;
1990 return p;
1991}
1992
1993template <typename T>
1994T
1995xpsi (T z)
1996{
1997 static const double euler_mascheroni
1998 = 0.577215664901532860606512090082402431042;
1999
2000 const bool is_int = (std::floor (z) == z);
2001
2002 T p = 0;
2003 if (z <= 0)
2004 {
2005 // limits - zeros of the gamma function
2006 if (is_int)
2007 p = -numeric_limits<T>::Inf (); // Matlab returns -Inf for psi (0)
2008 else
2009 // Abramowitz and Stegun, page 259, eq 6.3.7
2010 p = psi (1 - z) - (pi / tan (pi * z));
2011 }
2012 else if (is_int)
2013 {
2014 // Abramowitz and Stegun, page 258, eq 6.3.2
2015 p = - euler_mascheroni;
2016 for (octave_idx_type k = z - 1; k > 0; k--)
2017 p += 1.0 / k;
2018 }
2019 else if (z - std::floor (z) == 0.5)
2020 {
2021 // Abramowitz and Stegun, page 258, eq 6.3.3 and 6.3.4
2022 for (octave_idx_type k = z; k > 0; k--)
2023 p += 1.0 / (2 * k - 1);
2024
2025 p = - euler_mascheroni - 2 * std::log (2) + 2 * (p);
2026 }
2027 else
2028 {
2029 // adapted from XLiFE++ gammaFunctions
2030
2031 T zc = z;
2032 // Use formula for derivative of LogGamma(z)
2033 if (z < 10)
2034 {
2035 const signed char n = 10 - z;
2036 for (signed char k = n - 1; k >= 0; k--)
2037 p -= 1.0 / (k + z);
2038 zc += n;
2039 }
2040 p += lanczos_approximation_psi (zc);
2041 }
2042
2043 return p;
2044}
2045
2046// explicit instantiations
2047double
2048psi (double z) { return xpsi (z); }
2049float
2050psi (float z) { return xpsi (z); }
2051
2052template <typename T>
2053std::complex<T>
2054xpsi (const std::complex<T>& z)
2055{
2056 // adapted from XLiFE++ gammaFunctions
2057
2058 typedef typename std::complex<T>::value_type P;
2059
2060 P z_r = z.real ();
2061 P z_ra = z_r;
2062
2063 std::complex<T> dgam (0.0, 0.0);
2064 if (z.imag () == 0)
2065 dgam = std::complex<T> (psi (z_r), 0.0);
2066 else if (z_r < 0)
2067 dgam = psi (P (1.0) - z)- (P (pi) / tan (P (pi) * z));
2068 else
2069 {
2070 // Use formula for derivative of LogGamma(z)
2071 std::complex<T> z_m = z;
2072 if (z_ra < 8)
2073 {
2074 unsigned char n = 8 - z_ra;
2075 z_m = z + std::complex<T> (n, 0.0);
2076
2077 // Recurrence formula. For | Re(z) | < 8, use recursively
2078 //
2079 // DiGamma(z) = DiGamma(z+1) - 1/z
2080 std::complex<T> z_p = z + P (n - 1);
2081 for (unsigned char k = n; k > 0; k--, z_p -= 1.0)
2082 dgam -= P (1.0) / z_p;
2083 }
2084
2085 // for | Re(z) | > 8, use derivative of C.Lanczos expansion for
2086 // LogGamma
2087 //
2088 // psi(z) = log(z) - 1/(2z) - 1/12z^2 + 3/360z^4 - 5/1260z^6
2089 // + 7/1680z^8 - 9/1188z^10 + ...
2090 //
2091 // (Abramowitz&Stegun, page 259, formula 6.3.18
2092 dgam += lanczos_approximation_psi (z_m);
2093 }
2094 return dgam;
2095}
2096
2097// explicit instantiations
2098Complex
2099psi (const Complex& z) { return xpsi (z); }
2101psi (const FloatComplex& z) { return xpsi (z); }
2102
2103template <typename T>
2104static inline void
2105fortran_psifn (T z, octave_idx_type n, T& ans, octave_idx_type& ierr);
2106
2107template <>
2108inline void
2109fortran_psifn<double> (double z, octave_idx_type n_arg,
2110 double& ans, octave_idx_type& ierr)
2111{
2112 F77_INT n = to_f77_int (n_arg);
2113 F77_INT flag = 0;
2114 F77_INT t_ierr;
2115 F77_XFCN (dpsifn, DPSIFN, (z, n, 1, 1, ans, flag, t_ierr));
2116 ierr = t_ierr;
2117}
2118
2119template <>
2120inline void
2122 float& ans, octave_idx_type& ierr)
2123{
2124 F77_INT n = to_f77_int (n_arg);
2125 F77_INT flag = 0;
2126 F77_INT t_ierr;
2127 F77_XFCN (psifn, PSIFN, (z, n, 1, 1, ans, flag, t_ierr));
2128 ierr = t_ierr;
2129}
2130
2131template <typename T>
2132T
2134{
2135 T ans;
2137 fortran_psifn<T> (z, n, ans, ierr);
2138 if (ierr == 0)
2139 {
2140 // Remember that psifn and dpsifn return scales values
2141 // When n is 1: do nothing since ((-1)**(n+1)/gamma(n+1)) == 1
2142 // When n is 0: change sign since ((-1)**(n+1)/gamma(n+1)) == -1
2143 if (n > 1)
2144 // FIXME: xgamma here is a killer for our precision since it grows
2145 // way too fast.
2146 ans = ans / (std::pow (-1.0, n + 1) / gamma (double (n+1)));
2147 else if (n == 0)
2148 ans = -ans;
2149 }
2150 else if (ierr == 2)
2151 ans = - numeric_limits<T>::Inf ();
2152 else // we probably never get here
2153 ans = numeric_limits<T>::NaN ();
2154
2155 return ans;
2156}
2157
2158double
2159psi (octave_idx_type n, double z) { return xpsi (n, z); }
2160float
2161psi (octave_idx_type n, float z) { return xpsi (n, z); }
2162
2163Complex
2164rc_lgamma (double x)
2165{
2166 double result;
2167
2168#if defined (HAVE_LGAMMA_R)
2169 int sgngam;
2170 result = lgamma_r (x, &sgngam);
2171#else
2172 result = std::lgamma (x);
2173 int sgngam = signgam;
2174#endif
2175
2176 if (sgngam < 0 && std::isfinite (result))
2177 return Complex (result, M_PI);
2178 else
2179 return result;
2180}
2181
2184{
2185 float result;
2186
2187#if defined (HAVE_LGAMMAF_R)
2188 int sgngam;
2189 result = lgammaf_r (x, &sgngam);
2190#else
2191 result = std::lgammaf (x);
2192 int sgngam = signgam;
2193#endif
2194
2195 if (sgngam < 0 && std::isfinite (result))
2196 return FloatComplex (result, M_PI);
2197 else
2198 return result;
2199}
2200
2201Complex
2202rc_log1p (double x)
2203{
2204 return (x < -1.0
2205 ? Complex (std::log (-(1.0 + x)), M_PI)
2206 : Complex (log1p (x)));
2207}
2208
2211{
2212 return (x < -1.0f
2213 ? FloatComplex (std::log (-(1.0f + x)), M_PI)
2214 : FloatComplex (log1p (x)));
2215}
2216
2217OCTAVE_END_NAMESPACE(math)
2218OCTAVE_END_NAMESPACE(octave)
subroutine cairy(z, id, kode, ai, nz, ierr)
Definition cairy.f:2
subroutine cbesh(z, fnu, kode, m, n, cy, nz, ierr)
Definition cbesh.f:2
subroutine cbesi(z, fnu, kode, n, cy, nz, ierr)
Definition cbesi.f:2
subroutine cbesj(z, fnu, kode, n, cy, nz, ierr)
Definition cbesj.f:2
subroutine cbesk(z, fnu, kode, n, cy, nz, ierr)
Definition cbesk.f:2
subroutine cbesy(z, fnu, kode, n, cy, nz, cwrk, ierr)
Definition cbesy.f:2
subroutine cbiry(z, id, kode, bi, ierr)
Definition cbiry.f:2
N Dimensional Array with copy-on-write semantics.
Definition Array-base.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array-base.h:529
octave_idx_type rows() const
Definition Array-base.h:485
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
octave_idx_type cols() const
Definition Array-base.h:495
octave_idx_type numel() const
Number of elements in the array.
Definition Array-base.h:440
void resize(octave_idx_type nr, octave_idx_type nc, const Complex &rfv=Complex(0))
Definition CMatrix.h:191
void resize(octave_idx_type nr, octave_idx_type nc, const FloatComplex &rfv=FloatComplex(0))
Definition fCMatrix.h:199
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:341
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
subroutine dpsifn(x, n, kode, m, ans, nz, ierr)
Definition dpsifn.f:3
#define F77_CONST_CMPLX_ARG(x)
Definition f77-fcn.h:313
#define F77_CMPLX_ARG(x)
Definition f77-fcn.h:310
#define F77_XFCN(f, F, args)
Definition f77-fcn.h:45
octave_f77_int_type F77_INT
Definition f77-fcn.h:306
double lo_ieee_nan_value()
Definition lo-ieee.cc:84
std::complex< double > Dawson(std::complex< double > z, double relerr=0)
std::complex< double > w(std::complex< double > z, double relerr=0)
std::complex< double > erfi(std::complex< double > z, double relerr=0)
std::complex< double > erfc(std::complex< double > z, double relerr=0)
std::complex< double > erfcx(std::complex< double > z, double relerr=0)
std::complex< double > erf(std::complex< double > z, double relerr=0)
std::complex< double > Complex
Definition oct-cmplx.h:33
std::complex< float > FloatComplex
Definition oct-cmplx.h:34
Complex(* dptr)(const Complex &, double, int, octave_idx_type &)
void fortran_psifn< float >(float z, octave_idx_type n_arg, float &ans, octave_idx_type &ierr)
Complex besselj(double alpha, const Complex &x, bool scaled, octave_idx_type &ierr)
double erfinv(double x)
double erfi(double x)
Complex besselh2(double alpha, const Complex &x, bool scaled, octave_idx_type &ierr)
double gamma(double x)
double dawson(double x)
Complex erf(const Complex &x)
void fortran_psifn< double >(double z, octave_idx_type n_arg, double &ans, octave_idx_type &ierr)
double erfcinv(double x)
Complex rc_log1p(double x)
T xpsi(T z)
Complex bessely(double alpha, const Complex &x, bool scaled, octave_idx_type &ierr)
Complex besselk(double alpha, const Complex &x, bool scaled, octave_idx_type &ierr)
Complex besselh1(double alpha, const Complex &x, bool scaled, octave_idx_type &ierr)
Complex rc_lgamma(double x)
#define ALL_BESSEL(name, fcn)
FloatComplex(* fptr)(const FloatComplex &, float, int, octave_idx_type &)
Complex airy(const Complex &z, bool deriv, bool scaled, octave_idx_type &ierr)
double erfcx(double x)
Complex expm1(const Complex &x)
void ellipj(double u, double m, double &sn, double &cn, double &dn, double &err)
Complex besseli(double alpha, const Complex &x, bool scaled, octave_idx_type &ierr)
Complex biry(const Complex &z, bool deriv, bool scaled, octave_idx_type &ierr)
Complex log1p(const Complex &x)
Complex erfc(const Complex &x)
double psi(double z)
subroutine psifn(x, n, kode, m, ans, nz, ierr)
Definition psifn.f:3
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE const F77_INT F77_INT & ierr
F77_RET_T const F77_DBLE * x
F77_RET_T const F77_DBLE const F77_DBLE * f
F77_RET_T F77_FUNC(xerbla, XERBLA)(F77_CONST_CHAR_ARG_DEF(s_arg
subroutine zairy(zr, zi, id, kode, air, aii, nz, ierr)
Definition zairy.f:2
subroutine zbesh(zr, zi, fnu, kode, m, n, cyr, cyi, nz, ierr)
Definition zbesh.f:2
subroutine zbesi(zr, zi, fnu, kode, n, cyr, cyi, nz, ierr)
Definition zbesi.f:2
subroutine zbesj(zr, zi, fnu, kode, n, cyr, cyi, nz, ierr)
Definition zbesj.f:2
subroutine zbesk(zr, zi, fnu, kode, n, cyr, cyi, nz, ierr)
Definition zbesk.f:2
subroutine zbesy(zr, zi, fnu, kode, n, cyr, cyi, nz, cwrkr, cwrki, ierr)
Definition zbesy.f:3
subroutine zbiry(zr, zi, id, kode, bir, bii, ierr)
Definition zbiry.f:2