Mercurial > octave
changeset 23668:a6eef0626b2b
Promote simple functions from lo-specfun.cc to inline versions in lo-specfun.h.
* lo-specfun.cc (acosh, asinh, atanh, erf, erfc, lgamma, expm1, log1p, cbrt):
Delete functions.
* lo-specfun.cc: Alphabetize list of special functions.
* lo-specfun.cc (acosh, asinh, atanh, erf, erfc, lgamma, expm1, log1p, cbrt):
New inline functions that forward to std library.
* lo-specfun.h: Alphabetize list of special functions.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 21 Jun 2017 09:53:49 -0700 |
parents | 2d4a7ae1f6cd |
children | 94a4ba7b0d94 |
files | liboctave/numeric/lo-specfun.cc liboctave/numeric/lo-specfun.h |
diffstat | 2 files changed, 1206 insertions(+), 1261 deletions(-) [+] |
line wrap: on
line diff
--- a/liboctave/numeric/lo-specfun.cc Wed Jun 21 11:29:41 2017 -0400 +++ b/liboctave/numeric/lo-specfun.cc Wed Jun 21 09:53:49 2017 -0700 @@ -60,318 +60,6 @@ { namespace math { - double acosh (double x) { return std::acosh (x); } - - float acosh (float x) { return std::acoshf (x); } - - Complex acosh (const Complex& x) { return std::acosh (x); } - - FloatComplex acosh (const FloatComplex& x) { return std::acosh (x); } - - double asinh (double x) { return std::asinh (x); } - - float asinh (float x) { return std::asinhf (x); } - - Complex asinh (const Complex& x) { return std::asinh (x); } - - FloatComplex asinh (const FloatComplex& x) { return std::asinh (x); } - - double atanh (double x) { return std::atanh (x); } - - float atanh (float x) { return std::atanhf (x); } - - Complex atanh (const Complex& x) { return std::atanh (x); } - - FloatComplex atanh (const FloatComplex& x) { return std::atanh (x); } - - double erf (double x) { return std::erf (x); } - - float erf (float x) { return std::erff (x); } - - // Complex error function from the Faddeeva package - Complex - erf (const Complex& x) - { - return Faddeeva::erf (x); - } - - FloatComplex - erf (const FloatComplex& x) - { - Complex xd (x.real (), x.imag ()); - Complex ret = Faddeeva::erf (xd, std::numeric_limits<float>::epsilon ()); - return FloatComplex (ret.real (), ret.imag ()); - } - - double erfc (double x) { return std::erfc (x); } - - float erfc (float x) { return std::erfcf (x); } - - // Complex complementary error function from the Faddeeva package - Complex - erfc (const Complex& x) - { - return Faddeeva::erfc (x); - } - - FloatComplex - erfc (const FloatComplex& x) - { - Complex xd (x.real (), x.imag ()); - Complex ret = Faddeeva::erfc (xd, std::numeric_limits<float>::epsilon ()); - return FloatComplex (ret.real (), ret.imag ()); - } - - // Real and complex scaled complementary error function from Faddeeva pkg. - float erfcx (float x) { return Faddeeva::erfcx(x); } - double erfcx (double x) { return Faddeeva::erfcx(x); } - - Complex - erfcx (const Complex& x) - { - return Faddeeva::erfcx (x); - } - - FloatComplex - erfcx (const FloatComplex& x) - { - Complex xd (x.real (), x.imag ()); - Complex ret; - ret = Faddeeva::erfcx (xd, std::numeric_limits<float>::epsilon ()); - return FloatComplex (ret.real (), ret.imag ()); - } - - // Real and complex imaginary error function from Faddeeva package - float erfi (float x) { return Faddeeva::erfi(x); } - double erfi (double x) { return Faddeeva::erfi(x); } - - Complex - erfi (const Complex& x) - { - return Faddeeva::erfi (x); - } - - FloatComplex - erfi (const FloatComplex& x) - { - Complex xd (x.real (), x.imag ()); - Complex ret = Faddeeva::erfi (xd, std::numeric_limits<float>::epsilon ()); - return FloatComplex (ret.real (), ret.imag ()); - } - - // Real and complex Dawson function (= scaled erfi) from Faddeeva package - float dawson (float x) { return Faddeeva::Dawson(x); } - double dawson (double x) { return Faddeeva::Dawson(x); } - - Complex - dawson (const Complex& x) - { - return Faddeeva::Dawson (x); - } - - FloatComplex - dawson (const FloatComplex& x) - { - Complex xd (x.real (), x.imag ()); - Complex ret; - ret = Faddeeva::Dawson (xd, std::numeric_limits<float>::epsilon ()); - return FloatComplex (ret.real (), ret.imag ()); - } - - double - gamma (double x) - { - double result; - - // Special cases for (near) compatibility with Matlab instead of tgamma. - // Matlab does not have -0. - - if (x == 0) - result = (octave::math::negative_sign (x) - ? -octave::numeric_limits<double>::Inf () - : octave::numeric_limits<double>::Inf ()); - else if ((x < 0 && octave::math::x_nint (x) == x) - || octave::math::isinf (x)) - result = octave::numeric_limits<double>::Inf (); - else if (octave::math::isnan (x)) - result = octave::numeric_limits<double>::NaN (); - else - result = std::tgamma (x); - - return result; - } - - double lgamma (double x) { return std::lgamma (x); } - - Complex - rc_lgamma (double x) - { - double result; - -#if defined (HAVE_LGAMMA_R) - int sgngam; - result = lgamma_r (x, &sgngam); -#else - result = std::lgamma (x); - int sgngam = signgam; -#endif - - if (sgngam < 0) - return result + Complex (0., M_PI); - else - return result; - } - - float - gamma (float x) - { - float result; - - // Special cases for (near) compatibility with Matlab instead of tgamma. - // Matlab does not have -0. - - if (x == 0) - result = (octave::math::negative_sign (x) - ? -octave::numeric_limits<float>::Inf () - : octave::numeric_limits<float>::Inf ()); - else if ((x < 0 && octave::math::x_nint (x) == x) - || octave::math::isinf (x)) - result = octave::numeric_limits<float>::Inf (); - else if (octave::math::isnan (x)) - result = octave::numeric_limits<float>::NaN (); - else - result = std::tgammaf (x); - - return result; - } - - float lgamma (float x) { return std::lgammaf (x); } - - FloatComplex - rc_lgamma (float x) - { - float result; - -#if defined (HAVE_LGAMMAF_R) - int sgngam; - result = lgammaf_r (x, &sgngam); -#else - result = std::lgammaf (x); - int sgngam = signgam; -#endif - - if (sgngam < 0) - return result + FloatComplex (0., M_PI); - else - return result; - } - - double expm1 (double x) { return std::expm1 (x); } - - Complex - expm1 (const Complex& x) - { - Complex retval; - - if (std:: abs (x) < 1) - { - double im = x.imag (); - double u = expm1 (x.real ()); - double v = sin (im/2); - v = -2*v*v; - retval = Complex (u*v + u + v, (u+1) * sin (im)); - } - else - retval = std::exp (x) - Complex (1); - - return retval; - } - - float expm1 (float x) { return std::expm1f (x); } - - FloatComplex - expm1 (const FloatComplex& x) - { - FloatComplex retval; - - if (std:: abs (x) < 1) - { - float im = x.imag (); - float u = expm1 (x.real ()); - float v = sin (im/2); - v = -2*v*v; - retval = FloatComplex (u*v + u + v, (u+1) * sin (im)); - } - else - retval = std::exp (x) - FloatComplex (1); - - return retval; - } - - double log1p (double x) { return std::log1p (x); } - - Complex - log1p (const Complex& x) - { - Complex retval; - - double r = x.real (), i = x.imag (); - - if (fabs (r) < 0.5 && fabs (i) < 0.5) - { - double u = 2*r + r*r + i*i; - retval = Complex (log1p (u / (1+std::sqrt (u+1))), - atan2 (1 + r, i)); - } - else - retval = std::log (Complex (1) + x); - - return retval; - } - - double cbrt (double x) { return std::cbrt (x); } - - float log1p (float x) { return std::log1pf (x); } - - FloatComplex - log1p (const FloatComplex& x) - { - FloatComplex retval; - - float r = x.real (), i = x.imag (); - - if (fabs (r) < 0.5 && fabs (i) < 0.5) - { - float u = 2*r + r*r + i*i; - retval = FloatComplex (log1p (u / (1+std::sqrt (u+1))), - atan2 (1 + r, i)); - } - else - retval = std::log (FloatComplex (1) + x); - - return retval; - } - - float cbrt (float x) { return std::cbrtf (x); } - - static inline Complex - zbesj (const Complex& z, double alpha, int kode, octave_idx_type& ierr); - - static inline Complex - zbesy (const Complex& z, double alpha, int kode, octave_idx_type& ierr); - - static inline Complex - zbesi (const Complex& z, double alpha, int kode, octave_idx_type& ierr); - - static inline Complex - zbesk (const Complex& z, double alpha, int kode, octave_idx_type& ierr); - - static inline Complex - zbesh1 (const Complex& z, double alpha, int kode, octave_idx_type& ierr); - - static inline Complex - zbesh2 (const Complex& z, double alpha, int kode, octave_idx_type& ierr); - static inline Complex bessel_return_value (const Complex& val, octave_idx_type ierr) { @@ -404,6 +92,179 @@ return retval; } + static inline FloatComplex + bessel_return_value (const FloatComplex& val, octave_idx_type ierr) + { + static const FloatComplex inf_val + = FloatComplex (octave::numeric_limits<float>::Inf (), + octave::numeric_limits<float>::Inf ()); + + static const FloatComplex nan_val + = FloatComplex (octave::numeric_limits<float>::NaN (), + octave::numeric_limits<float>::NaN ()); + + FloatComplex retval; + + switch (ierr) + { + case 0: + case 3: + retval = val; + break; + + case 2: + retval = inf_val; + break; + + default: + retval = nan_val; + break; + } + + return retval; + } + + + + Complex + airy (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr) + { + double ar = 0.0; + double ai = 0.0; + + double zr = z.real (); + double zi = z.imag (); + + F77_INT id = (deriv ? 1 : 0); + F77_INT nz, t_ierr; + + F77_FUNC (zairy, ZAIRY) (zr, zi, id, 2, ar, ai, nz, t_ierr); + + ierr = t_ierr; + + if (! scaled) + { + Complex expz = exp (- 2.0 / 3.0 * z * sqrt (z)); + + double rexpz = expz.real (); + double iexpz = expz.imag (); + + double tmp = ar*rexpz - ai*iexpz; + + ai = ar*iexpz + ai*rexpz; + ar = tmp; + } + + if (zi == 0.0 && (! scaled || zr >= 0.0)) + ai = 0.0; + + return bessel_return_value (Complex (ar, ai), ierr); + } + + ComplexMatrix + airy (const ComplexMatrix& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + octave_idx_type nr = z.rows (); + octave_idx_type nc = z.cols (); + + ComplexMatrix retval (nr, nc); + + ierr.resize (dim_vector (nr, nc)); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + retval(i,j) = airy (z(i,j), deriv, scaled, ierr(i,j)); + + return retval; + } + + ComplexNDArray + airy (const ComplexNDArray& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + dim_vector dv = z.dims (); + octave_idx_type nel = dv.numel (); + ComplexNDArray retval (dv); + + ierr.resize (dv); + + for (octave_idx_type i = 0; i < nel; i++) + retval(i) = airy (z(i), deriv, scaled, ierr(i)); + + return retval; + } + + FloatComplex + airy (const FloatComplex& z, bool deriv, bool scaled, + octave_idx_type& ierr) + { + FloatComplex a; + + F77_INT id = (deriv ? 1 : 0); + F77_INT nz, t_ierr; + + F77_FUNC (cairy, CAIRY) (F77_CONST_CMPLX_ARG (&z), id, 2, + F77_CMPLX_ARG (&a), nz, t_ierr); + + ierr = t_ierr; + + float ar = a.real (); + float ai = a.imag (); + + if (! scaled) + { + FloatComplex expz = exp (- 2.0f / 3.0f * z * sqrt (z)); + + float rexpz = expz.real (); + float iexpz = expz.imag (); + + float tmp = ar*rexpz - ai*iexpz; + + ai = ar*iexpz + ai*rexpz; + ar = tmp; + } + + if (z.imag () == 0.0 && (! scaled || z.real () >= 0.0)) + ai = 0.0; + + return bessel_return_value (FloatComplex (ar, ai), ierr); + } + + FloatComplexMatrix + airy (const FloatComplexMatrix& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + octave_idx_type nr = z.rows (); + octave_idx_type nc = z.cols (); + + FloatComplexMatrix retval (nr, nc); + + ierr.resize (dim_vector (nr, nc)); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + retval(i,j) = airy (z(i,j), deriv, scaled, ierr(i,j)); + + return retval; + } + + FloatComplexNDArray + airy (const FloatComplexNDArray& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + dim_vector dv = z.dims (); + octave_idx_type nel = dv.numel (); + FloatComplexNDArray retval (dv); + + ierr.resize (dv); + + for (octave_idx_type i = 0; i < nel; i++) + retval(i) = airy (z(i), deriv, scaled, ierr(i)); + + return retval; + } + static inline bool is_integer_value (double x) { @@ -411,6 +272,24 @@ } static inline Complex + zbesj (const Complex& z, double alpha, int kode, octave_idx_type& ierr); + + static inline Complex + zbesy (const Complex& z, double alpha, int kode, octave_idx_type& ierr); + + static inline Complex + zbesi (const Complex& z, double alpha, int kode, octave_idx_type& ierr); + + static inline Complex + zbesk (const Complex& z, double alpha, int kode, octave_idx_type& ierr); + + static inline Complex + zbesh1 (const Complex& z, double alpha, int kode, octave_idx_type& ierr); + + static inline Complex + zbesh2 (const Complex& z, double alpha, int kode, octave_idx_type& ierr); + + static inline Complex zbesj (const Complex& z, double alpha, int kode, octave_idx_type& ierr) { Complex retval; @@ -1026,38 +905,6 @@ static inline FloatComplex cbesh2 (const FloatComplex& z, float alpha, int kode, octave_idx_type& ierr); - static inline FloatComplex - bessel_return_value (const FloatComplex& val, octave_idx_type ierr) - { - static const FloatComplex inf_val - = FloatComplex (octave::numeric_limits<float>::Inf (), - octave::numeric_limits<float>::Inf ()); - - static const FloatComplex nan_val - = FloatComplex (octave::numeric_limits<float>::NaN (), - octave::numeric_limits<float>::NaN ()); - - FloatComplex retval; - - switch (ierr) - { - case 0: - case 3: - retval = val; - break; - - case 2: - retval = inf_val; - break; - - default: - retval = nan_val; - break; - } - - return retval; - } - static inline bool is_integer_value (float x) { @@ -1355,7 +1202,7 @@ if (alpha >= 0.0) { - FloatComplex y = 0.0; + FloatComplex y = 0.0;; F77_INT nz, t_ierr; @@ -1642,285 +1489,6 @@ #undef NN_BESSEL #undef RC_BESSEL - Complex - airy (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr) - { - double ar = 0.0; - double ai = 0.0; - - double zr = z.real (); - double zi = z.imag (); - - F77_INT id = (deriv ? 1 : 0); - F77_INT nz, t_ierr; - - F77_FUNC (zairy, ZAIRY) (zr, zi, id, 2, ar, ai, nz, t_ierr); - - ierr = t_ierr; - - if (! scaled) - { - Complex expz = exp (- 2.0 / 3.0 * z * sqrt (z)); - - double rexpz = expz.real (); - double iexpz = expz.imag (); - - double tmp = ar*rexpz - ai*iexpz; - - ai = ar*iexpz + ai*rexpz; - ar = tmp; - } - - if (zi == 0.0 && (! scaled || zr >= 0.0)) - ai = 0.0; - - return bessel_return_value (Complex (ar, ai), ierr); - } - - Complex - biry (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr) - { - double ar = 0.0; - double ai = 0.0; - - double zr = z.real (); - double zi = z.imag (); - - F77_INT id = (deriv ? 1 : 0); - F77_INT t_ierr; - - F77_FUNC (zbiry, ZBIRY) (zr, zi, id, 2, ar, ai, t_ierr); - - ierr = t_ierr; - - if (! scaled) - { - Complex expz = exp (std::abs (std::real (2.0 / 3.0 * z * sqrt (z)))); - - double rexpz = expz.real (); - double iexpz = expz.imag (); - - double tmp = ar*rexpz - ai*iexpz; - - ai = ar*iexpz + ai*rexpz; - ar = tmp; - } - - if (zi == 0.0 && (! scaled || zr >= 0.0)) - ai = 0.0; - - return bessel_return_value (Complex (ar, ai), ierr); - } - - ComplexMatrix - airy (const ComplexMatrix& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - octave_idx_type nr = z.rows (); - octave_idx_type nc = z.cols (); - - ComplexMatrix retval (nr, nc); - - ierr.resize (dim_vector (nr, nc)); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - retval(i,j) = airy (z(i,j), deriv, scaled, ierr(i,j)); - - return retval; - } - - ComplexMatrix - biry (const ComplexMatrix& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - octave_idx_type nr = z.rows (); - octave_idx_type nc = z.cols (); - - ComplexMatrix retval (nr, nc); - - ierr.resize (dim_vector (nr, nc)); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - retval(i,j) = biry (z(i,j), deriv, scaled, ierr(i,j)); - - return retval; - } - - ComplexNDArray - airy (const ComplexNDArray& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - dim_vector dv = z.dims (); - octave_idx_type nel = dv.numel (); - ComplexNDArray retval (dv); - - ierr.resize (dv); - - for (octave_idx_type i = 0; i < nel; i++) - retval(i) = airy (z(i), deriv, scaled, ierr(i)); - - return retval; - } - - ComplexNDArray - biry (const ComplexNDArray& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - dim_vector dv = z.dims (); - octave_idx_type nel = dv.numel (); - ComplexNDArray retval (dv); - - ierr.resize (dv); - - for (octave_idx_type i = 0; i < nel; i++) - retval(i) = biry (z(i), deriv, scaled, ierr(i)); - - return retval; - } - - FloatComplex - airy (const FloatComplex& z, bool deriv, bool scaled, - octave_idx_type& ierr) - { - FloatComplex a; - - F77_INT id = (deriv ? 1 : 0); - F77_INT nz, t_ierr; - - F77_FUNC (cairy, CAIRY) (F77_CONST_CMPLX_ARG (&z), id, 2, - F77_CMPLX_ARG (&a), nz, t_ierr); - - ierr = t_ierr; - - float ar = a.real (); - float ai = a.imag (); - - if (! scaled) - { - FloatComplex expz = exp (- 2.0f / 3.0f * z * sqrt (z)); - - float rexpz = expz.real (); - float iexpz = expz.imag (); - - float tmp = ar*rexpz - ai*iexpz; - - ai = ar*iexpz + ai*rexpz; - ar = tmp; - } - - if (z.imag () == 0.0 && (! scaled || z.real () >= 0.0)) - ai = 0.0; - - return bessel_return_value (FloatComplex (ar, ai), ierr); - } - - FloatComplex - biry (const FloatComplex& z, bool deriv, bool scaled, - octave_idx_type& ierr) - { - FloatComplex a; - - F77_INT id = (deriv ? 1 : 0); - F77_INT t_ierr; - - F77_FUNC (cbiry, CBIRY) (F77_CONST_CMPLX_ARG (&z), id, 2, - F77_CMPLX_ARG (&a), t_ierr); - - ierr = t_ierr; - - float ar = a.real (); - float ai = a.imag (); - - if (! scaled) - { - FloatComplex expz - = exp (std::abs (std::real (2.0f / 3.0f * z * sqrt (z)))); - - float rexpz = expz.real (); - float iexpz = expz.imag (); - - float tmp = ar*rexpz - ai*iexpz; - - ai = ar*iexpz + ai*rexpz; - ar = tmp; - } - - if (z.imag () == 0.0 && (! scaled || z.real () >= 0.0)) - ai = 0.0; - - return bessel_return_value (FloatComplex (ar, ai), ierr); - } - - FloatComplexMatrix - airy (const FloatComplexMatrix& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - octave_idx_type nr = z.rows (); - octave_idx_type nc = z.cols (); - - FloatComplexMatrix retval (nr, nc); - - ierr.resize (dim_vector (nr, nc)); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - retval(i,j) = airy (z(i,j), deriv, scaled, ierr(i,j)); - - return retval; - } - - FloatComplexMatrix - biry (const FloatComplexMatrix& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - octave_idx_type nr = z.rows (); - octave_idx_type nc = z.cols (); - - FloatComplexMatrix retval (nr, nc); - - ierr.resize (dim_vector (nr, nc)); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - retval(i,j) = biry (z(i,j), deriv, scaled, ierr(i,j)); - - return retval; - } - - FloatComplexNDArray - airy (const FloatComplexNDArray& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - dim_vector dv = z.dims (); - octave_idx_type nel = dv.numel (); - FloatComplexNDArray retval (dv); - - ierr.resize (dv); - - for (octave_idx_type i = 0; i < nel; i++) - retval(i) = airy (z(i), deriv, scaled, ierr(i)); - - return retval; - } - - FloatComplexNDArray - biry (const FloatComplexNDArray& z, bool deriv, bool scaled, - Array<octave_idx_type>& ierr) - { - dim_vector dv = z.dims (); - octave_idx_type nel = dv.numel (); - FloatComplexNDArray retval (dv); - - ierr.resize (dv); - - for (octave_idx_type i = 0; i < nel; i++) - retval(i) = biry (z(i), deriv, scaled, ierr(i)); - - return retval; - } - OCTAVE_NORETURN static void err_betainc_nonconformant (const dim_vector& d1, const dim_vector& d2, const dim_vector& d3) @@ -2229,521 +1797,6 @@ return retval; } - // FIXME: there is still room for improvement here... - - double - gammainc (double x, double a, bool& err) - { - if (a < 0.0 || x < 0.0) - (*current_liboctave_error_handler) - ("gammainc: A and X must be non-negative"); - - err = false; - - double retval; - - F77_XFCN (xgammainc, XGAMMAINC, (a, x, retval)); - - return retval; - } - - Matrix - gammainc (double x, const Matrix& a) - { - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - Matrix retval (nr, nc); - - bool err; - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - retval(i,j) = gammainc (x, a(i,j), err); - - if (err) - return Matrix (); - } - - return retval; - } - - Matrix - gammainc (const Matrix& x, double a) - { - octave_idx_type nr = x.rows (); - octave_idx_type nc = x.cols (); - - Matrix retval (nr, nc); - - bool err; - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - retval(i,j) = gammainc (x(i,j), a, err); - - if (err) - return Matrix (); - } - - return retval; - } - - Matrix - gammainc (const Matrix& x, const Matrix& a) - { - octave_idx_type nr = x.rows (); - octave_idx_type nc = x.cols (); - - octave_idx_type a_nr = a.rows (); - octave_idx_type a_nc = a.cols (); - - if (nr != a_nr || nc != a_nc) - (*current_liboctave_error_handler) - ("gammainc: nonconformant arguments (arg 1 is %dx%d, arg 2 is %dx%d)", - nr, nc, a_nr, a_nc); - - Matrix retval (nr, nc); - - bool err; - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - retval(i,j) = gammainc (x(i,j), a(i,j), err); - - if (err) - return Matrix (); - } - - return retval; - } - - NDArray - gammainc (double x, const NDArray& a) - { - dim_vector dv = a.dims (); - octave_idx_type nel = dv.numel (); - - NDArray retval (dv); - - bool err; - - for (octave_idx_type i = 0; i < nel; i++) - { - retval(i) = gammainc (x, a(i), err); - - if (err) - return NDArray (); - } - - return retval; - } - - NDArray - gammainc (const NDArray& x, double a) - { - dim_vector dv = x.dims (); - octave_idx_type nel = dv.numel (); - - NDArray retval (dv); - - bool err; - - for (octave_idx_type i = 0; i < nel; i++) - { - retval(i) = gammainc (x(i), a, err); - - if (err) - return NDArray (); - } - - return retval; - } - - NDArray - gammainc (const NDArray& x, const NDArray& a) - { - dim_vector dv = x.dims (); - octave_idx_type nel = dv.numel (); - - if (dv != a.dims ()) - { - std::string x_str = dv.str (); - std::string a_str = a.dims ().str (); - - (*current_liboctave_error_handler) - ("gammainc: nonconformant arguments (arg 1 is %s, arg 2 is %s)", - x_str.c_str (), a_str.c_str ()); - } - - NDArray retval (dv); - - bool err; - - for (octave_idx_type i = 0; i < nel; i++) - { - retval(i) = gammainc (x(i), a(i), err); - - if (err) - return NDArray (); - } - - return retval; - } - - float - gammainc (float x, float a, bool& err) - { - if (a < 0.0 || x < 0.0) - (*current_liboctave_error_handler) - ("gammainc: A and X must be non-negative"); - - err = false; - - float retval; - - F77_XFCN (xsgammainc, XSGAMMAINC, (a, x, retval)); - - return retval; - } - - FloatMatrix - gammainc (float x, const FloatMatrix& a) - { - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - FloatMatrix retval (nr, nc); - - bool err; - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - retval(i,j) = gammainc (x, a(i,j), err); - - if (err) - return FloatMatrix (); - } - - return retval; - } - - FloatMatrix - gammainc (const FloatMatrix& x, float a) - { - octave_idx_type nr = x.rows (); - octave_idx_type nc = x.cols (); - - FloatMatrix retval (nr, nc); - - bool err; - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - retval(i,j) = gammainc (x(i,j), a, err); - - if (err) - return FloatMatrix (); - } - - return retval; - } - - FloatMatrix - gammainc (const FloatMatrix& x, const FloatMatrix& a) - { - octave_idx_type nr = x.rows (); - octave_idx_type nc = x.cols (); - - octave_idx_type a_nr = a.rows (); - octave_idx_type a_nc = a.cols (); - - if (nr != a_nr || nc != a_nc) - (*current_liboctave_error_handler) - ("gammainc: nonconformant arguments (arg 1 is %dx%d, arg 2 is %dx%d)", - nr, nc, a_nr, a_nc); - - FloatMatrix retval (nr, nc); - - bool err; - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - retval(i,j) = gammainc (x(i,j), a(i,j), err); - - if (err) - return FloatMatrix (); - } - - return retval; - } - - FloatNDArray - gammainc (float x, const FloatNDArray& a) - { - dim_vector dv = a.dims (); - octave_idx_type nel = dv.numel (); - - FloatNDArray retval (dv); - - bool err; - - for (octave_idx_type i = 0; i < nel; i++) - { - retval(i) = gammainc (x, a(i), err); - - if (err) - return FloatNDArray (); - } - - return retval; - } - - FloatNDArray - gammainc (const FloatNDArray& x, float a) - { - dim_vector dv = x.dims (); - octave_idx_type nel = dv.numel (); - - FloatNDArray retval (dv); - - bool err; - - for (octave_idx_type i = 0; i < nel; i++) - { - retval(i) = gammainc (x(i), a, err); - - if (err) - return FloatNDArray (); - } - - return retval; - } - - FloatNDArray - gammainc (const FloatNDArray& x, const FloatNDArray& a) - { - dim_vector dv = x.dims (); - octave_idx_type nel = dv.numel (); - - if (dv != a.dims ()) - { - std::string x_str = dv.str (); - std::string a_str = a.dims ().str (); - - (*current_liboctave_error_handler) - ("gammainc: nonconformant arguments (arg 1 is %s, arg 2 is %s)", - x_str.c_str (), a_str.c_str ()); - } - - FloatNDArray retval (dv); - - bool err; - - for (octave_idx_type i = 0; i < nel; i++) - { - retval(i) = gammainc (x(i), a(i), err); - - if (err) - return FloatNDArray (); - } - - return retval; - } - - Complex rc_log1p (double x) - { - const double pi = 3.14159265358979323846; - return (x < -1.0 - ? Complex (std::log (-(1.0 + x)), pi) - : Complex (log1p (x))); - } - - FloatComplex rc_log1p (float x) - { - const float pi = 3.14159265358979323846f; - return (x < -1.0f - ? FloatComplex (std::log (-(1.0f + x)), pi) - : FloatComplex (log1p (x))); - } - - // This algorithm is due to P. J. Acklam. - // - // See http://home.online.no/~pjacklam/notes/invnorm/ - // - // The rational approximation has relative accuracy 1.15e-9 in the whole - // region. For doubles, it is refined by a single step of Halley's 3rd - // order method. For single precision, the accuracy is already OK, so - // we skip it to get faster evaluation. - - static double do_erfinv (double x, bool refine) - { - // Coefficients of rational approximation. - static const double a[] = - { - -2.806989788730439e+01, 1.562324844726888e+02, - -1.951109208597547e+02, 9.783370457507161e+01, - -2.168328665628878e+01, 1.772453852905383e+00 - }; - static const double b[] = - { - -5.447609879822406e+01, 1.615858368580409e+02, - -1.556989798598866e+02, 6.680131188771972e+01, - -1.328068155288572e+01 - }; - static const double c[] = - { - -5.504751339936943e-03, -2.279687217114118e-01, - -1.697592457770869e+00, -1.802933168781950e+00, - 3.093354679843505e+00, 2.077595676404383e+00 - }; - static const double d[] = - { - 7.784695709041462e-03, 3.224671290700398e-01, - 2.445134137142996e+00, 3.754408661907416e+00 - }; - - static const double spi2 = 8.862269254527579e-01; // sqrt(pi)/2. - static const double pbreak = 0.95150; - double ax = fabs (x), y; - - // Select case. - if (ax <= pbreak) - { - // Middle region. - const double q = 0.5 * x, r = q*q; - const double yn = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q; - const double yd = ((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0; - y = yn / yd; - } - else if (ax < 1.0) - { - // Tail region. - const double q = std::sqrt (-2*std::log (0.5*(1-ax))); - const double yn = ((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5]; - const double yd = (((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0; - y = yn / yd * octave::math::signum (-x); - } - else if (ax == 1.0) - return octave::numeric_limits<double>::Inf () * octave::math::signum (x); - else - return octave::numeric_limits<double>::NaN (); - - if (refine) - { - // One iteration of Halley's method gives full precision. - double u = (erf (y) - x) * spi2 * exp (y*y); - y -= u / (1 + y*u); - } - - return y; - } - - double erfinv (double x) - { - return do_erfinv (x, true); - } - - float erfinv (float x) - { - return do_erfinv (x, false); - } - - // The algorthim for erfcinv is an adaptation of the erfinv algorithm - // above from P. J. Acklam. It has been modified to run over the - // different input domain of erfcinv. See the notes for erfinv for an - // explanation. - - static double do_erfcinv (double x, bool refine) - { - // Coefficients of rational approximation. - static const double a[] = - { - -2.806989788730439e+01, 1.562324844726888e+02, - -1.951109208597547e+02, 9.783370457507161e+01, - -2.168328665628878e+01, 1.772453852905383e+00 - }; - static const double b[] = - { - -5.447609879822406e+01, 1.615858368580409e+02, - -1.556989798598866e+02, 6.680131188771972e+01, - -1.328068155288572e+01 - }; - static const double c[] = - { - -5.504751339936943e-03, -2.279687217114118e-01, - -1.697592457770869e+00, -1.802933168781950e+00, - 3.093354679843505e+00, 2.077595676404383e+00 - }; - static const double d[] = - { - 7.784695709041462e-03, 3.224671290700398e-01, - 2.445134137142996e+00, 3.754408661907416e+00 - }; - - static const double spi2 = 8.862269254527579e-01; // sqrt(pi)/2. - static const double pbreak_lo = 0.04850; // 1-pbreak - static const double pbreak_hi = 1.95150; // 1+pbreak - double y; - - // Select case. - if (x >= pbreak_lo && x <= pbreak_hi) - { - // Middle region. - const double q = 0.5*(1-x), r = q*q; - const double yn = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q; - const double yd = ((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0; - y = yn / yd; - } - else if (x > 0.0 && x < 2.0) - { - // Tail region. - const double q = (x < 1 - ? std::sqrt (-2*std::log (0.5*x)) - : std::sqrt (-2*std::log (0.5*(2-x)))); - - const double yn = ((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5]; - - const double yd = (((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0; - - y = yn / yd; - - if (x < pbreak_lo) - y = -y; - } - else if (x == 0.0) - return octave::numeric_limits<double>::Inf (); - else if (x == 2.0) - return -octave::numeric_limits<double>::Inf (); - else - return octave::numeric_limits<double>::NaN (); - - if (refine) - { - // One iteration of Halley's method gives full precision. - double u = (erf (y) - (1-x)) * spi2 * exp (y*y); - y -= u / (1 + y*u); - } - - return y; - } - - double erfcinv (double x) - { - return do_erfcinv (x, true); - } - - float erfcinv (float x) - { - return do_erfcinv (x, false); - } - // // Incomplete Beta function ratio // @@ -3195,6 +2248,165 @@ return retval; } + Complex + biry (const Complex& z, bool deriv, bool scaled, octave_idx_type& ierr) + { + double ar = 0.0; + double ai = 0.0; + + double zr = z.real (); + double zi = z.imag (); + + F77_INT id = (deriv ? 1 : 0); + F77_INT t_ierr; + + F77_FUNC (zbiry, ZBIRY) (zr, zi, id, 2, ar, ai, t_ierr); + + ierr = t_ierr; + + if (! scaled) + { + Complex expz = exp (std::abs (std::real (2.0 / 3.0 * z * sqrt (z)))); + + double rexpz = expz.real (); + double iexpz = expz.imag (); + + double tmp = ar*rexpz - ai*iexpz; + + ai = ar*iexpz + ai*rexpz; + ar = tmp; + } + + if (zi == 0.0 && (! scaled || zr >= 0.0)) + ai = 0.0; + + return bessel_return_value (Complex (ar, ai), ierr); + } + + ComplexMatrix + biry (const ComplexMatrix& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + octave_idx_type nr = z.rows (); + octave_idx_type nc = z.cols (); + + ComplexMatrix retval (nr, nc); + + ierr.resize (dim_vector (nr, nc)); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + retval(i,j) = biry (z(i,j), deriv, scaled, ierr(i,j)); + + return retval; + } + + ComplexNDArray + biry (const ComplexNDArray& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + dim_vector dv = z.dims (); + octave_idx_type nel = dv.numel (); + ComplexNDArray retval (dv); + + ierr.resize (dv); + + for (octave_idx_type i = 0; i < nel; i++) + retval(i) = biry (z(i), deriv, scaled, ierr(i)); + + return retval; + } + + FloatComplex + biry (const FloatComplex& z, bool deriv, bool scaled, + octave_idx_type& ierr) + { + FloatComplex a; + + F77_INT id = (deriv ? 1 : 0); + F77_INT t_ierr; + + F77_FUNC (cbiry, CBIRY) (F77_CONST_CMPLX_ARG (&z), id, 2, + F77_CMPLX_ARG (&a), t_ierr); + + ierr = t_ierr; + + float ar = a.real (); + float ai = a.imag (); + + if (! scaled) + { + FloatComplex expz + = exp (std::abs (std::real (2.0f / 3.0f * z * sqrt (z)))); + + float rexpz = expz.real (); + float iexpz = expz.imag (); + + float tmp = ar*rexpz - ai*iexpz; + + ai = ar*iexpz + ai*rexpz; + ar = tmp; + } + + if (z.imag () == 0.0 && (! scaled || z.real () >= 0.0)) + ai = 0.0; + + return bessel_return_value (FloatComplex (ar, ai), ierr); + } + + FloatComplexMatrix + biry (const FloatComplexMatrix& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + octave_idx_type nr = z.rows (); + octave_idx_type nc = z.cols (); + + FloatComplexMatrix retval (nr, nc); + + ierr.resize (dim_vector (nr, nc)); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + retval(i,j) = biry (z(i,j), deriv, scaled, ierr(i,j)); + + return retval; + } + + FloatComplexNDArray + biry (const FloatComplexNDArray& z, bool deriv, bool scaled, + Array<octave_idx_type>& ierr) + { + dim_vector dv = z.dims (); + octave_idx_type nel = dv.numel (); + FloatComplexNDArray retval (dv); + + ierr.resize (dv); + + for (octave_idx_type i = 0; i < nel; i++) + retval(i) = biry (z(i), deriv, scaled, ierr(i)); + + return retval; + } + + // Real and complex Dawson function (= scaled erfi) from Faddeeva package + double dawson (double x) { return Faddeeva::Dawson (x); } + float dawson (float x) { return Faddeeva::Dawson (x); } + + Complex + dawson (const Complex& x) + { + return Faddeeva::Dawson (x); + } + + FloatComplex + dawson (const FloatComplex& x) + { + Complex xd (x.real (), x.imag ()); + Complex ret; + ret = Faddeeva::Dawson (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (ret.real (), ret.imag ()); + } + void ellipj (double u, double m, double& sn, double& cn, double& dn, double& err) { @@ -3295,6 +2507,694 @@ } } + // Complex error function from the Faddeeva package + Complex + erf (const Complex& x) + { + return Faddeeva::erf (x); + } + + FloatComplex + erf (const FloatComplex& x) + { + Complex xd (x.real (), x.imag ()); + Complex ret = Faddeeva::erf (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (ret.real (), ret.imag ()); + } + + // Complex complementary error function from the Faddeeva package + Complex + erfc (const Complex& x) + { + return Faddeeva::erfc (x); + } + + FloatComplex + erfc (const FloatComplex& x) + { + Complex xd (x.real (), x.imag ()); + Complex ret = Faddeeva::erfc (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (ret.real (), ret.imag ()); + } + + // The algorthim for erfcinv is an adaptation of the erfinv algorithm + // above from P. J. Acklam. It has been modified to run over the + // different input domain of erfcinv. See the notes for erfinv for an + // explanation. + + static double do_erfcinv (double x, bool refine) + { + // Coefficients of rational approximation. + static const double a[] = + { + -2.806989788730439e+01, 1.562324844726888e+02, + -1.951109208597547e+02, 9.783370457507161e+01, + -2.168328665628878e+01, 1.772453852905383e+00 + }; + static const double b[] = + { + -5.447609879822406e+01, 1.615858368580409e+02, + -1.556989798598866e+02, 6.680131188771972e+01, + -1.328068155288572e+01 + }; + static const double c[] = + { + -5.504751339936943e-03, -2.279687217114118e-01, + -1.697592457770869e+00, -1.802933168781950e+00, + 3.093354679843505e+00, 2.077595676404383e+00 + }; + static const double d[] = + { + 7.784695709041462e-03, 3.224671290700398e-01, + 2.445134137142996e+00, 3.754408661907416e+00 + }; + + static const double spi2 = 8.862269254527579e-01; // sqrt(pi)/2. + static const double pbreak_lo = 0.04850; // 1-pbreak + static const double pbreak_hi = 1.95150; // 1+pbreak + double y; + + // Select case. + if (x >= pbreak_lo && x <= pbreak_hi) + { + // Middle region. + const double q = 0.5*(1-x), r = q*q; + const double yn = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q; + const double yd = ((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0; + y = yn / yd; + } + else if (x > 0.0 && x < 2.0) + { + // Tail region. + const double q = (x < 1 + ? std::sqrt (-2*std::log (0.5*x)) + : std::sqrt (-2*std::log (0.5*(2-x)))); + + const double yn = ((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5]; + + const double yd = (((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0; + + y = yn / yd; + + if (x < pbreak_lo) + y = -y; + } + else if (x == 0.0) + return octave::numeric_limits<double>::Inf (); + else if (x == 2.0) + return -octave::numeric_limits<double>::Inf (); + else + return octave::numeric_limits<double>::NaN (); + + if (refine) + { + // One iteration of Halley's method gives full precision. + double u = (erf (y) - (1-x)) * spi2 * exp (y*y); + y -= u / (1 + y*u); + } + + return y; + } + + double erfcinv (double x) + { + return do_erfcinv (x, true); + } + + float erfcinv (float x) + { + return do_erfcinv (x, false); + } + + // Real and complex scaled complementary error function from Faddeeva pkg. + double erfcx (double x) { return Faddeeva::erfcx (x); } + float erfcx (float x) { return Faddeeva::erfcx (x); } + + Complex + erfcx (const Complex& x) + { + return Faddeeva::erfcx (x); + } + + FloatComplex + erfcx (const FloatComplex& x) + { + Complex xd (x.real (), x.imag ()); + Complex ret; + ret = Faddeeva::erfcx (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (ret.real (), ret.imag ()); + } + + // Real and complex imaginary error function from Faddeeva package + double erfi (double x) { return Faddeeva::erfi (x); } + float erfi (float x) { return Faddeeva::erfi (x); } + + Complex + erfi (const Complex& x) + { + return Faddeeva::erfi (x); + } + + FloatComplex + erfi (const FloatComplex& x) + { + Complex xd (x.real (), x.imag ()); + Complex ret = Faddeeva::erfi (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (ret.real (), ret.imag ()); + } + + // This algorithm is due to P. J. Acklam. + // + // See http://home.online.no/~pjacklam/notes/invnorm/ + // + // The rational approximation has relative accuracy 1.15e-9 in the whole + // region. For doubles, it is refined by a single step of Halley's 3rd + // order method. For single precision, the accuracy is already OK, so + // we skip it to get faster evaluation. + + static double do_erfinv (double x, bool refine) + { + // Coefficients of rational approximation. + static const double a[] = + { + -2.806989788730439e+01, 1.562324844726888e+02, + -1.951109208597547e+02, 9.783370457507161e+01, + -2.168328665628878e+01, 1.772453852905383e+00 + }; + static const double b[] = + { + -5.447609879822406e+01, 1.615858368580409e+02, + -1.556989798598866e+02, 6.680131188771972e+01, + -1.328068155288572e+01 + }; + static const double c[] = + { + -5.504751339936943e-03, -2.279687217114118e-01, + -1.697592457770869e+00, -1.802933168781950e+00, + 3.093354679843505e+00, 2.077595676404383e+00 + }; + static const double d[] = + { + 7.784695709041462e-03, 3.224671290700398e-01, + 2.445134137142996e+00, 3.754408661907416e+00 + }; + + static const double spi2 = 8.862269254527579e-01; // sqrt(pi)/2. + static const double pbreak = 0.95150; + double ax = fabs (x), y; + + // Select case. + if (ax <= pbreak) + { + // Middle region. + const double q = 0.5 * x, r = q*q; + const double yn = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q; + const double yd = ((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0; + y = yn / yd; + } + else if (ax < 1.0) + { + // Tail region. + const double q = std::sqrt (-2*std::log (0.5*(1-ax))); + const double yn = ((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5]; + const double yd = (((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0; + y = yn / yd * octave::math::signum (-x); + } + else if (ax == 1.0) + return octave::numeric_limits<double>::Inf () * octave::math::signum (x); + else + return octave::numeric_limits<double>::NaN (); + + if (refine) + { + // One iteration of Halley's method gives full precision. + double u = (erf (y) - x) * spi2 * exp (y*y); + y -= u / (1 + y*u); + } + + return y; + } + + double erfinv (double x) + { + return do_erfinv (x, true); + } + + float erfinv (float x) + { + return do_erfinv (x, false); + } + + Complex + expm1 (const Complex& x) + { + Complex retval; + + if (std:: abs (x) < 1) + { + double im = x.imag (); + double u = expm1 (x.real ()); + double v = sin (im/2); + v = -2*v*v; + retval = Complex (u*v + u + v, (u+1) * sin (im)); + } + else + retval = std::exp (x) - Complex (1); + + return retval; + } + + FloatComplex + expm1 (const FloatComplex& x) + { + FloatComplex retval; + + if (std:: abs (x) < 1) + { + float im = x.imag (); + float u = expm1 (x.real ()); + float v = sin (im/2); + v = -2*v*v; + retval = FloatComplex (u*v + u + v, (u+1) * sin (im)); + } + else + retval = std::exp (x) - FloatComplex (1); + + return retval; + } + + double + gamma (double x) + { + double result; + + // Special cases for (near) compatibility with Matlab instead of tgamma. + // Matlab does not have -0. + + if (x == 0) + result = (octave::math::negative_sign (x) + ? -octave::numeric_limits<double>::Inf () + : octave::numeric_limits<double>::Inf ()); + else if ((x < 0 && octave::math::x_nint (x) == x) + || octave::math::isinf (x)) + result = octave::numeric_limits<double>::Inf (); + else if (octave::math::isnan (x)) + result = octave::numeric_limits<double>::NaN (); + else + result = std::tgamma (x); + + return result; + } + + float + gamma (float x) + { + float result; + + // Special cases for (near) compatibility with Matlab instead of tgamma. + // Matlab does not have -0. + + if (x == 0) + result = (octave::math::negative_sign (x) + ? -octave::numeric_limits<float>::Inf () + : octave::numeric_limits<float>::Inf ()); + else if ((x < 0 && octave::math::x_nint (x) == x) + || octave::math::isinf (x)) + result = octave::numeric_limits<float>::Inf (); + else if (octave::math::isnan (x)) + result = octave::numeric_limits<float>::NaN (); + else + result = std::tgammaf (x); + + return result; + } + + // FIXME: there is still room for improvement here... + + double + gammainc (double x, double a, bool& err) + { + if (a < 0.0 || x < 0.0) + (*current_liboctave_error_handler) + ("gammainc: A and X must be non-negative"); + + err = false; + + double retval; + + F77_XFCN (xgammainc, XGAMMAINC, (a, x, retval)); + + return retval; + } + + Matrix + gammainc (double x, const Matrix& a) + { + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + Matrix retval (nr, nc); + + bool err; + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + retval(i,j) = gammainc (x, a(i,j), err); + + if (err) + return Matrix (); + } + + return retval; + } + + Matrix + gammainc (const Matrix& x, double a) + { + octave_idx_type nr = x.rows (); + octave_idx_type nc = x.cols (); + + Matrix retval (nr, nc); + + bool err; + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + retval(i,j) = gammainc (x(i,j), a, err); + + if (err) + return Matrix (); + } + + return retval; + } + + Matrix + gammainc (const Matrix& x, const Matrix& a) + { + octave_idx_type nr = x.rows (); + octave_idx_type nc = x.cols (); + + octave_idx_type a_nr = a.rows (); + octave_idx_type a_nc = a.cols (); + + if (nr != a_nr || nc != a_nc) + (*current_liboctave_error_handler) + ("gammainc: nonconformant arguments (arg 1 is %dx%d, arg 2 is %dx%d)", + nr, nc, a_nr, a_nc); + + Matrix retval (nr, nc); + + bool err; + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + retval(i,j) = gammainc (x(i,j), a(i,j), err); + + if (err) + return Matrix (); + } + + return retval; + } + + NDArray + gammainc (double x, const NDArray& a) + { + dim_vector dv = a.dims (); + octave_idx_type nel = dv.numel (); + + NDArray retval (dv); + + bool err; + + for (octave_idx_type i = 0; i < nel; i++) + { + retval(i) = gammainc (x, a(i), err); + + if (err) + return NDArray (); + } + + return retval; + } + + NDArray + gammainc (const NDArray& x, double a) + { + dim_vector dv = x.dims (); + octave_idx_type nel = dv.numel (); + + NDArray retval (dv); + + bool err; + + for (octave_idx_type i = 0; i < nel; i++) + { + retval(i) = gammainc (x(i), a, err); + + if (err) + return NDArray (); + } + + return retval; + } + + NDArray + gammainc (const NDArray& x, const NDArray& a) + { + dim_vector dv = x.dims (); + octave_idx_type nel = dv.numel (); + + if (dv != a.dims ()) + { + std::string x_str = dv.str (); + std::string a_str = a.dims ().str (); + + (*current_liboctave_error_handler) + ("gammainc: nonconformant arguments (arg 1 is %s, arg 2 is %s)", + x_str.c_str (), a_str.c_str ()); + } + + NDArray retval (dv); + + bool err; + + for (octave_idx_type i = 0; i < nel; i++) + { + retval(i) = gammainc (x(i), a(i), err); + + if (err) + return NDArray (); + } + + return retval; + } + + float + gammainc (float x, float a, bool& err) + { + if (a < 0.0 || x < 0.0) + (*current_liboctave_error_handler) + ("gammainc: A and X must be non-negative"); + + err = false; + + float retval; + + F77_XFCN (xsgammainc, XSGAMMAINC, (a, x, retval)); + + return retval; + } + + FloatMatrix + gammainc (float x, const FloatMatrix& a) + { + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + FloatMatrix retval (nr, nc); + + bool err; + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + retval(i,j) = gammainc (x, a(i,j), err); + + if (err) + return FloatMatrix (); + } + + return retval; + } + + FloatMatrix + gammainc (const FloatMatrix& x, float a) + { + octave_idx_type nr = x.rows (); + octave_idx_type nc = x.cols (); + + FloatMatrix retval (nr, nc); + + bool err; + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + retval(i,j) = gammainc (x(i,j), a, err); + + if (err) + return FloatMatrix (); + } + + return retval; + } + + FloatMatrix + gammainc (const FloatMatrix& x, const FloatMatrix& a) + { + octave_idx_type nr = x.rows (); + octave_idx_type nc = x.cols (); + + octave_idx_type a_nr = a.rows (); + octave_idx_type a_nc = a.cols (); + + if (nr != a_nr || nc != a_nc) + (*current_liboctave_error_handler) + ("gammainc: nonconformant arguments (arg 1 is %dx%d, arg 2 is %dx%d)", + nr, nc, a_nr, a_nc); + + FloatMatrix retval (nr, nc); + + bool err; + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + retval(i,j) = gammainc (x(i,j), a(i,j), err); + + if (err) + return FloatMatrix (); + } + + return retval; + } + + FloatNDArray + gammainc (float x, const FloatNDArray& a) + { + dim_vector dv = a.dims (); + octave_idx_type nel = dv.numel (); + + FloatNDArray retval (dv); + + bool err; + + for (octave_idx_type i = 0; i < nel; i++) + { + retval(i) = gammainc (x, a(i), err); + + if (err) + return FloatNDArray (); + } + + return retval; + } + + FloatNDArray + gammainc (const FloatNDArray& x, float a) + { + dim_vector dv = x.dims (); + octave_idx_type nel = dv.numel (); + + FloatNDArray retval (dv); + + bool err; + + for (octave_idx_type i = 0; i < nel; i++) + { + retval(i) = gammainc (x(i), a, err); + + if (err) + return FloatNDArray (); + } + + return retval; + } + + FloatNDArray + gammainc (const FloatNDArray& x, const FloatNDArray& a) + { + dim_vector dv = x.dims (); + octave_idx_type nel = dv.numel (); + + if (dv != a.dims ()) + { + std::string x_str = dv.str (); + std::string a_str = a.dims ().str (); + + (*current_liboctave_error_handler) + ("gammainc: nonconformant arguments (arg 1 is %s, arg 2 is %s)", + x_str.c_str (), a_str.c_str ()); + } + + FloatNDArray retval (dv); + + bool err; + + for (octave_idx_type i = 0; i < nel; i++) + { + retval(i) = gammainc (x(i), a(i), err); + + if (err) + return FloatNDArray (); + } + + return retval; + } + + Complex + log1p (const Complex& x) + { + Complex retval; + + double r = x.real (), i = x.imag (); + + if (fabs (r) < 0.5 && fabs (i) < 0.5) + { + double u = 2*r + r*r + i*i; + retval = Complex (log1p (u / (1+std::sqrt (u+1))), + atan2 (1 + r, i)); + } + else + retval = std::log (Complex (1) + x); + + return retval; + } + + FloatComplex + log1p (const FloatComplex& x) + { + FloatComplex retval; + + float r = x.real (), i = x.imag (); + + if (fabs (r) < 0.5 && fabs (i) < 0.5) + { + float u = 2*r + r*r + i*i; + retval = FloatComplex (log1p (u / (1+std::sqrt (u+1))), + atan2 (1 + r, i)); + } + else + retval = std::log (FloatComplex (1) + x); + + return retval; + } + static const double pi = 3.14159265358979323846; template <typename T> @@ -3508,6 +3408,60 @@ double psi (octave_idx_type n, double z) { return xpsi (n, z); } float psi (octave_idx_type n, float z) { return xpsi (n, z); } + + Complex + rc_lgamma (double x) + { + double result; + +#if defined (HAVE_LGAMMA_R) + int sgngam; + result = lgamma_r (x, &sgngam); +#else + result = std::lgamma (x); + int sgngam = signgam; +#endif + + if (sgngam < 0) + return result + Complex (0., M_PI); + else + return result; + } + + FloatComplex + rc_lgamma (float x) + { + float result; + +#if defined (HAVE_LGAMMAF_R) + int sgngam; + result = lgammaf_r (x, &sgngam); +#else + result = std::lgammaf (x); + int sgngam = signgam; +#endif + + if (sgngam < 0) + return result + FloatComplex (0., M_PI); + else + return result; + } + + Complex rc_log1p (double x) + { + const double pi = 3.14159265358979323846; + return (x < -1.0 + ? Complex (std::log (-(1.0 + x)), pi) + : Complex (log1p (x))); + } + + FloatComplex rc_log1p (float x) + { + const float pi = 3.14159265358979323846f; + return (x < -1.0f + ? FloatComplex (std::log (-(1.0f + x)), pi) + : FloatComplex (log1p (x))); + } } }
--- a/liboctave/numeric/lo-specfun.h Wed Jun 21 11:29:41 2017 -0400 +++ b/liboctave/numeric/lo-specfun.h Wed Jun 21 09:53:49 2017 -0700 @@ -46,53 +46,33 @@ { namespace math { - extern OCTAVE_API double acosh (double x); - extern OCTAVE_API float acosh (float x); - extern OCTAVE_API Complex acosh (const Complex& x); - extern OCTAVE_API FloatComplex acosh (const FloatComplex& x); - - extern OCTAVE_API double asinh (double x); - extern OCTAVE_API float asinh (float x); - extern OCTAVE_API Complex asinh (const Complex& x); - extern OCTAVE_API FloatComplex asinh (const FloatComplex& x); - - extern OCTAVE_API double atanh (double x); - extern OCTAVE_API float atanh (float x); - extern OCTAVE_API Complex atanh (const Complex& x); - extern OCTAVE_API FloatComplex atanh (const FloatComplex& x); - - extern OCTAVE_API double erf (double x); - extern OCTAVE_API float erf (float x); - extern OCTAVE_API Complex erf (const Complex& x); - extern OCTAVE_API FloatComplex erf (const FloatComplex& x); + inline double acosh (double x) { return std::acosh (x); } + inline float acosh (float x) { return std::acoshf (x); } + inline Complex acosh (const Complex& x) { return std::acosh (x); } + inline FloatComplex acosh (const FloatComplex& x) { return std::acosh (x); } - extern OCTAVE_API double erfc (double x); - extern OCTAVE_API float erfc (float x); - extern OCTAVE_API Complex erfc (const Complex& x); - extern OCTAVE_API FloatComplex erfc (const FloatComplex& x); - - extern OCTAVE_API double expm1 (double x); - extern OCTAVE_API Complex expm1 (const Complex& x); - - extern OCTAVE_API float expm1 (float x); - extern OCTAVE_API FloatComplex expm1 (const FloatComplex& x); - - extern OCTAVE_API double log1p (double x); - extern OCTAVE_API Complex log1p (const Complex& x); + extern OCTAVE_API Complex airy (const Complex& z, bool deriv, bool scaled, + octave_idx_type& ierr); + extern OCTAVE_API ComplexMatrix airy (const ComplexMatrix& z, bool deriv, + bool scaled, Array<octave_idx_type>& ierr); + extern OCTAVE_API ComplexNDArray airy (const ComplexNDArray& z, bool deriv, + bool scaled, Array<octave_idx_type>& ierr); + extern OCTAVE_API FloatComplex airy (const FloatComplex& z, bool deriv, + bool scaled, octave_idx_type& ierr); + extern OCTAVE_API FloatComplexMatrix airy (const FloatComplexMatrix& z, + bool deriv, bool scaled, Array<octave_idx_type>& ierr); + extern OCTAVE_API FloatComplexNDArray airy (const FloatComplexNDArray& z, + bool deriv, bool scaled, Array<octave_idx_type>& ierr); - extern OCTAVE_API float log1p (float x); - extern OCTAVE_API FloatComplex log1p (const FloatComplex& x); - - extern OCTAVE_API double cbrt (double x); - extern OCTAVE_API float cbrt (float x); + inline double asinh (double x) { return std::asinh (x); } + inline float asinh (float x) { return std::asinhf (x); } + inline Complex asinh (const Complex& x) { return std::asinh (x); } + inline FloatComplex asinh (const FloatComplex& x) { return std::asinh (x); } - extern OCTAVE_API double gamma (double x); - extern OCTAVE_API double lgamma (double x); - extern OCTAVE_API Complex rc_lgamma (double x); - - extern OCTAVE_API float gamma (float x); - extern OCTAVE_API float lgamma (float x); - extern OCTAVE_API FloatComplex rc_lgamma (float x); + inline double atanh (double x) { return std::atanh (x); } + inline float atanh (float x) { return std::atanhf (x); } + inline Complex atanh (const Complex& x) { return std::atanh (x); } + inline FloatComplex atanh (const FloatComplex& x) { return std::atanh (x); } extern OCTAVE_API Complex besselj (double alpha, const Complex& x, bool scaled, octave_idx_type& ierr); @@ -302,36 +282,6 @@ extern OCTAVE_API FloatComplexMatrix besselh2 (const FloatRowVector& alpha, const FloatComplexColumnVector& x, bool scaled, Array<octave_idx_type>& ierr); - extern OCTAVE_API Complex airy (const Complex& z, bool deriv, bool scaled, - octave_idx_type& ierr); - extern OCTAVE_API Complex biry (const Complex& z, bool deriv, bool scaled, - octave_idx_type& ierr); - - extern OCTAVE_API ComplexMatrix airy (const ComplexMatrix& z, bool deriv, - bool scaled, Array<octave_idx_type>& ierr); - extern OCTAVE_API ComplexMatrix biry (const ComplexMatrix& z, bool deriv, - bool scaled, Array<octave_idx_type>& ierr); - - extern OCTAVE_API ComplexNDArray airy (const ComplexNDArray& z, bool deriv, - bool scaled, Array<octave_idx_type>& ierr); - extern OCTAVE_API ComplexNDArray biry (const ComplexNDArray& z, bool deriv, - bool scaled, Array<octave_idx_type>& ierr); - - extern OCTAVE_API FloatComplex airy (const FloatComplex& z, bool deriv, - bool scaled, octave_idx_type& ierr); - extern OCTAVE_API FloatComplex biry (const FloatComplex& z, bool deriv, - bool scaled, octave_idx_type& ierr); - - extern OCTAVE_API FloatComplexMatrix airy (const FloatComplexMatrix& z, - bool deriv, bool scaled, Array<octave_idx_type>& ierr); - extern OCTAVE_API FloatComplexMatrix biry (const FloatComplexMatrix& z, - bool deriv, bool scaled, Array<octave_idx_type>& ierr); - - extern OCTAVE_API FloatComplexNDArray airy (const FloatComplexNDArray& z, - bool deriv, bool scaled, Array<octave_idx_type>& ierr); - extern OCTAVE_API FloatComplexNDArray biry (const FloatComplexNDArray& z, - bool deriv, bool scaled, Array<octave_idx_type>& ierr); - extern OCTAVE_API double betainc (double x, double a, double b); extern OCTAVE_API Array<double> betainc (double x, double a, const Array<double>& b); @@ -339,7 +289,6 @@ double b); extern OCTAVE_API Array<double> betainc (double x, const Array<double>& a, const Array<double>& b); - extern OCTAVE_API Array<double> betainc (const Array<double>& x, double a, double b); extern OCTAVE_API Array<double> betainc (const Array<double>& x, double a, @@ -356,7 +305,6 @@ float b); extern OCTAVE_API Array<float> betainc (float x, const Array<float>& a, const Array<float>& b); - extern OCTAVE_API Array<float> betainc (const Array<float>& x, float a, float b); extern OCTAVE_API Array<float> betainc (const Array<float>& x, float a, @@ -366,6 +314,83 @@ extern OCTAVE_API Array<float> betainc (const Array<float>& x, const Array<float>& a, const Array<float>& b); + extern OCTAVE_API double betaincinv (double x, double a, double b); + extern OCTAVE_API Array<double> betaincinv (double x, double a, + const Array<double>& b); + extern OCTAVE_API Array<double> betaincinv (double x, const Array<double>& a, + double b); + extern OCTAVE_API Array<double> betaincinv (double x, const Array<double>& a, + const Array<double>& b); + + extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, double a, + double b); + extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, double a, + const Array<double>& b); + extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, + const Array<double>& a, double b); + extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, + const Array<double>& a, const Array<double>& b); + + extern OCTAVE_API Complex biry (const Complex& z, bool deriv, bool scaled, + octave_idx_type& ierr); + extern OCTAVE_API ComplexMatrix biry (const ComplexMatrix& z, bool deriv, + bool scaled, Array<octave_idx_type>& ierr); + extern OCTAVE_API ComplexNDArray biry (const ComplexNDArray& z, bool deriv, + bool scaled, Array<octave_idx_type>& ierr); + extern OCTAVE_API FloatComplex biry (const FloatComplex& z, bool deriv, + bool scaled, octave_idx_type& ierr); + extern OCTAVE_API FloatComplexMatrix biry (const FloatComplexMatrix& z, + bool deriv, bool scaled, Array<octave_idx_type>& ierr); + extern OCTAVE_API FloatComplexNDArray biry (const FloatComplexNDArray& z, + bool deriv, bool scaled, Array<octave_idx_type>& ierr); + + inline double cbrt (double x) { return std::cbrt (x); } + inline float cbrt (float x) { return std::cbrtf (x); } + + extern OCTAVE_API double dawson (double x); + extern OCTAVE_API float dawson (float x); + extern OCTAVE_API Complex dawson (const Complex& x); + extern OCTAVE_API FloatComplex dawson (const FloatComplex& x); + + extern OCTAVE_API void ellipj (double u, double m, double& sn, double& cn, + double& dn, double& err); + extern OCTAVE_API void ellipj (const Complex& u, double m, Complex& sn, + Complex& cn, Complex& dn, double& err); + + inline double erf (double x) { return std::erf (x); } + inline float erf (float x) { return std::erff (x); } + extern OCTAVE_API Complex erf (const Complex& x); + extern OCTAVE_API FloatComplex erf (const FloatComplex& x); + + inline double erfc (double x) { return std::erfc (x); } + inline float erfc (float x) { return std::erfcf (x); } + extern OCTAVE_API Complex erfc (const Complex& x); + extern OCTAVE_API FloatComplex erfc (const FloatComplex& x); + + extern OCTAVE_API double erfcinv (double x); + extern OCTAVE_API float erfcinv (float x); + + extern OCTAVE_API double erfcx (double x); + extern OCTAVE_API float erfcx (float x); + extern OCTAVE_API Complex erfcx (const Complex& x); + extern OCTAVE_API FloatComplex erfcx (const FloatComplex& x); + + extern OCTAVE_API double erfi (double x); + extern OCTAVE_API float erfi (float x); + extern OCTAVE_API Complex erfi (const Complex& x); + extern OCTAVE_API FloatComplex erfi (const FloatComplex& x); + + extern OCTAVE_API double erfinv (double x); + extern OCTAVE_API float erfinv (float x); + + inline double expm1 (double x) { return std::expm1 (x); } + inline float expm1 (float x) { return std::expm1f (x); } + extern OCTAVE_API Complex expm1 (const Complex& x); + extern OCTAVE_API FloatComplex expm1 (const FloatComplex& x); + + extern OCTAVE_API double gamma (double x); + extern OCTAVE_API float gamma (float x); + extern OCTAVE_API double gammainc (double x, double a, bool& err); inline double gammainc (double x, double a) { @@ -398,60 +423,26 @@ extern OCTAVE_API FloatNDArray gammainc (const FloatNDArray& x, const FloatNDArray& a); - extern OCTAVE_API Complex rc_log1p (double x); - extern OCTAVE_API FloatComplex rc_log1p (float x); - - extern OCTAVE_API double erfinv (double x); - extern OCTAVE_API float erfinv (float x); - - extern OCTAVE_API double erfcinv (double x); - extern OCTAVE_API float erfcinv (float x); - - extern OCTAVE_API float erfcx (float x); - extern OCTAVE_API double erfcx (double x); - extern OCTAVE_API Complex erfcx (const Complex& x); - extern OCTAVE_API FloatComplex erfcx (const FloatComplex& x); - - extern OCTAVE_API float erfi (float x); - extern OCTAVE_API double erfi (double x); - extern OCTAVE_API Complex erfi (const Complex& x); - extern OCTAVE_API FloatComplex erfi (const FloatComplex& x); + inline double lgamma (double x) { return std::lgamma (x); } + inline float lgamma (float x) { return std::lgammaf (x); } - extern OCTAVE_API float dawson (float x); - extern OCTAVE_API double dawson (double x); - extern OCTAVE_API Complex dawson (const Complex& x); - extern OCTAVE_API FloatComplex dawson (const FloatComplex& x); - - extern OCTAVE_API double betaincinv (double x, double a, double b); - extern OCTAVE_API Array<double> betaincinv (double x, double a, - const Array<double>& b); - extern OCTAVE_API Array<double> betaincinv (double x, const Array<double>& a, - double b); - extern OCTAVE_API Array<double> betaincinv (double x, const Array<double>& a, - const Array<double>& b); - - extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, double a, - double b); - extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, double a, - const Array<double>& b); - extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, - const Array<double>& a, double b); - extern OCTAVE_API Array<double> betaincinv (const Array<double>& x, - const Array<double>& a, const Array<double>& b); - - extern OCTAVE_API void ellipj (double u, double m, double& sn, double& cn, - double& dn, double& err); - extern OCTAVE_API void ellipj (const Complex& u, double m, Complex& sn, - Complex& cn, Complex& dn, double& err); + inline double log1p (double x) { return std::log1p (x); } + inline float log1p (float x) { return std::log1pf (x); } + extern OCTAVE_API Complex log1p (const Complex& x); + extern OCTAVE_API FloatComplex log1p (const FloatComplex& x); extern OCTAVE_API double psi (double x); extern OCTAVE_API float psi (float x); - extern OCTAVE_API Complex psi (const Complex& x); extern OCTAVE_API FloatComplex psi (const FloatComplex& x); - extern OCTAVE_API double psi (octave_idx_type n, double z); extern OCTAVE_API float psi (octave_idx_type n, float z); + + extern OCTAVE_API Complex rc_lgamma (double x); + extern OCTAVE_API FloatComplex rc_lgamma (float x); + + extern OCTAVE_API Complex rc_log1p (double x); + extern OCTAVE_API FloatComplex rc_log1p (float x); } }