Mercurial > hg > octave-lyh
diff liboctave/numeric/lo-specfun.cc @ 15696:2fac72a256ce
Add complex erf,erfc,erfcx,erfi,dawson routines from Faddeeva package.
* libinterp/corefcn/mappers.cc: Add erfi and dawson mapper functions,
and add complex-argument test cases for erf, erfc, erfcx, erfi, and
dawson.
* libinterp/octave-value/ov-base.cc, libinterp/octave-value/ov-base.h:
Add erfi and dawson mapper functions.
* libinterp/octave-value/ov-complex.cc, libinterp/octave-value/ov-cx-mat.cc,
libinterp/octave-value/ov-cx-sparse.cc, libinterp/octave-value/ov-float.cc,
libinterp/octave-value/ov-flt-complex.cc,
libinterp/octave-value/ov-flt-cx-mat.cc,
libinterp/octave-value/ov-flt-re-mat.cc,
libinterp/octave-value/ov-re-mat.c,
libinterp/octave-value/ov-re-sparse.cc,
libinterp/octave-value/ov-scalar.cc,
libinterp/octave-value/ov.h:
Support erf, erfc, erfcx, erfi, and dawson mapper functions for
real and complex matrices and scalars.
* liboctave/cruft/Faddeeva/Faddeeva.cc, liboctave/cruft/Faddeeva/Faddeeva.hh:
liboctave/cruft/Faddeeva/module.mk, liboctave/cruft/Makefile.am:
Add Faddeeva package (from http://ab-initio.mit.edu/Faddeeva) to
libcruft, to provide the various complex-argument error functions.
* liboctave/numeric/lo-specfun.cc, liboctave/numeric/lo-specfun.h:
Add complex-argument erf, erfc, erfcx, erfi, and dawson functions
to liboctave API. Delete previous real-argument erfcx implementation
in favor of Faddeeva::erfcx (which seems to be slightly faster
in gcc/x86-64 benchmarks, with similar accuracy).
* doc/interpreter/arith.txi: Include erfi and dawson documentation.
author | Steven G. Johnson <stevenj@alum.mit.edu> |
---|---|
date | Tue, 27 Nov 2012 23:39:54 -0500 |
parents | 648dabbb4c6b |
children | cd115ec92248 |
line wrap: on
line diff
--- a/liboctave/numeric/lo-specfun.cc +++ b/liboctave/numeric/lo-specfun.cc @@ -50,6 +50,8 @@ #define M_PI 3.14159265358979323846 #endif +#include "Faddeeva.hh" + extern "C" { F77_RET_T @@ -287,6 +289,82 @@ } #endif +// Complex error function from the Faddeeva package +Complex +erf (const Complex& x) +{ + return Faddeeva::erf (x); +} +FloatComplex +erf (const FloatComplex& x) +{ + Complex xd (real (x), imag (x)); + Complex ret = Faddeeva::erf (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (real (ret), imag (ret)); +} + +// Complex complementary error function from the Faddeeva package +Complex +erfc (const Complex& x) +{ + return Faddeeva::erfc (x); +} +FloatComplex +erfc (const FloatComplex& x) +{ + Complex xd (real (x), imag (x)); + Complex ret = Faddeeva::erfc (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (real (ret), imag (ret)); +} + +// Real and complex scaled complementary error function from Faddeeva package +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 (real (x), imag (x)); + Complex ret = Faddeeva::erfcx (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (real (ret), imag (ret)); +} + +// 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 (real (x), imag (x)); + Complex ret = Faddeeva::erfi (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (real (ret), imag (ret)); +} + +// 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 (real (x), imag (x)); + Complex ret = Faddeeva::Dawson (xd, std::numeric_limits<float>::epsilon ()); + return FloatComplex (real (ret), imag (ret)); +} + double xgamma (double x) { @@ -3029,106 +3107,6 @@ return do_erfcinv (x, false); } -// Implementation based on the Fortran code by W.J.Cody -// see http://www.netlib.org/specfun/erf. -// Templatized and simplified workflow. - -// FIXME: Maybe this should be globally visible. -static inline float erfc (float x) { return erfcf (x); } - -template <class T> -static T -erfcx_impl (T x) -{ - static const T c[] = - { - 5.64188496988670089e-1,8.88314979438837594, - 6.61191906371416295e+1,2.98635138197400131e+2, - 8.81952221241769090e+2,1.71204761263407058e+3, - 2.05107837782607147e+3,1.23033935479799725e+3, - 2.15311535474403846e-8 - }; - - static const T d[] = - { - 1.57449261107098347e+1,1.17693950891312499e+2, - 5.37181101862009858e+2,1.62138957456669019e+3, - 3.29079923573345963e+3,4.36261909014324716e+3, - 3.43936767414372164e+3,1.23033935480374942e+3 - }; - - static const T p[] = - { - 3.05326634961232344e-1,3.60344899949804439e-1, - 1.25781726111229246e-1,1.60837851487422766e-2, - 6.58749161529837803e-4,1.63153871373020978e-2 - }; - - static const T q[] = - { - 2.56852019228982242,1.87295284992346047, - 5.27905102951428412e-1,6.05183413124413191e-2, - 2.33520497626869185e-3 - }; - - static const T sqrpi = 5.6418958354775628695e-1; - static const T xhuge = sqrt (1.0 / std::numeric_limits<T>::epsilon ()); - static const T xneg = -sqrt (log (std::numeric_limits<T>::max ()/2.0)); - - double y = fabs (x), result; - if (x < xneg) - result = octave_Inf; - else if (y <= 0.46875) - result = std::exp (x*x) * erfc (x); - else - { - if (y <= 4.0) - { - double xnum = c[8]*y, xden = y; - for (int i = 0; i < 7; i++) - { - xnum = (xnum + c[i]) * y; - xden = (xden + d[i]) * y; - } - - result = (xnum + c[7]) / (xden + d[7]); - } - else if (y <= xhuge) - { - double y2 = 1/(y*y), xnum = p[5]*y2, xden = y2; - for (int i = 0; i < 4; i++) - { - xnum = (xnum + p[i]) * y2; - xden = (xden + q[i]) * y2; - } - - result = y2 * (xnum + p[4]) / (xden + q[4]); - result = (sqrpi - result) / y; - } - else - result = sqrpi / y; - - // Fix up negative argument. - if (x < 0) - { - double y2 = ceil (x / 16.0) * 16.0, del = (x-y2)*(x+y2); - result = 2*(std::exp (y2*y2) * std::exp (del)) - result; - } - } - - return result; -} - -double erfcx (double x) -{ - return erfcx_impl (x); -} - -float erfcx (float x) -{ - return erfcx_impl (x); -} - // // Incomplete Beta function ratio //