|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once |
|
|
|
#include "config.h" |
|
#include "error.h" |
|
|
|
#include "cephes/const.h" |
|
|
|
|
|
namespace xsf { |
|
|
|
|
|
XSF_HOST_DEVICE inline double exp1(double x) { |
|
|
|
|
|
|
|
|
|
|
|
int k, m; |
|
double e1, r, t, t0; |
|
constexpr double ga = cephes::detail::SCIPY_EULER; |
|
|
|
if (x == 0.0) { |
|
return std::numeric_limits<double>::infinity(); |
|
} |
|
if (x <= 1.0) { |
|
e1 = 1.0; |
|
r = 1.0; |
|
for (k = 1; k < 26; k++) { |
|
r = -r*k*x/std::pow(k+1.0, 2); |
|
e1 += r; |
|
if (std::abs(r) <= std::abs(e1)*1e-15) { break; } |
|
} |
|
return -ga - std::log(x) + x*e1; |
|
} |
|
m = 20 + (int)(80.0/x); |
|
t0 = 0.0; |
|
for (k = m; k > 0; k--) { |
|
t0 = k / (1.0 + k / (x+t0)); |
|
} |
|
t = 1.0 / (x + t0); |
|
return std::exp(-x)*t; |
|
} |
|
|
|
XSF_HOST_DEVICE inline float exp1(float x) { return exp1(static_cast<double>(x)); } |
|
|
|
XSF_HOST_DEVICE inline std::complex<double> exp1(std::complex<double> z) { |
|
|
|
|
|
|
|
|
|
|
|
constexpr double el = cephes::detail::SCIPY_EULER; |
|
int k; |
|
std::complex<double> ce1, cr, zc, zd, zdc; |
|
double x = z.real(); |
|
double a0 = std::abs(z); |
|
|
|
|
|
double xt = -2.0*std::abs(z.imag()); |
|
|
|
if (a0 == 0.0) { return std::numeric_limits<double>::infinity(); } |
|
if ((a0 < 5.0) || ((x < xt) && (a0 < 40.0))) { |
|
|
|
ce1 = 1.0; |
|
cr = 1.0; |
|
for (k = 1; k < 501; k++) { |
|
cr = -cr*z*static_cast<double>(k / std::pow(k + 1, 2)); |
|
ce1 += cr; |
|
if (std::abs(cr) < std::abs(ce1)*1e-15) { break; } |
|
} |
|
if ((x <= 0.0) && (z.imag() == 0.0)) { |
|
|
|
|
|
ce1 = -el - std::log(-z) + z*ce1 - std::copysign(M_PI, z.imag())*std::complex<double>(0.0, 1.0); |
|
} else { |
|
ce1 = -el - std::log(z) + z*ce1; |
|
} |
|
} else { |
|
|
|
|
|
|
|
|
|
zc = 0.0; |
|
zd = static_cast<double>(1) / z; |
|
zdc = zd; |
|
zc += zdc; |
|
for (k = 1; k < 501; k++) { |
|
zd = static_cast<double>(1) / (zd*static_cast<double>(k) + static_cast<double>(1)); |
|
zdc *= (zd - static_cast<double>(1)); |
|
zc += zdc; |
|
|
|
zd = static_cast<double>(1) / (zd*static_cast<double>(k) + z); |
|
zdc *= (z*zd - static_cast<double>(1)); |
|
zc += zdc; |
|
if ((std::abs(zdc) <= std::abs(zc)*1e-15) && (k > 20)) { break; } |
|
} |
|
ce1 = std::exp(-z)*zc; |
|
if ((x <= 0.0) && (z.imag() == 0.0)) { |
|
ce1 -= M_PI*std::complex<double>(0.0, 1.0); |
|
} |
|
} |
|
return ce1; |
|
} |
|
|
|
XSF_HOST_DEVICE inline std::complex<float> exp1(std::complex<float> z) { |
|
return static_cast<std::complex<float>>(exp1(static_cast<std::complex<double>>(z))); |
|
} |
|
|
|
XSF_HOST_DEVICE inline double expi(double x) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
constexpr double ga = cephes::detail::SCIPY_EULER; |
|
double ei, r; |
|
|
|
if (x == 0.0) { |
|
ei = -std::numeric_limits<double>::infinity(); |
|
} else if (x < 0) { |
|
ei = -exp1(-x); |
|
} else if (std::abs(x) <= 40.0) { |
|
|
|
ei = 1.0; |
|
r = 1.0; |
|
|
|
for (int k = 1; k <= 100; k++) { |
|
r = r * k * x / ((k + 1.0) * (k + 1.0)); |
|
ei += r; |
|
if (std::abs(r / ei) <= 1.0e-15) { break; } |
|
} |
|
ei = ga + std::log(x) + x * ei; |
|
} else { |
|
|
|
ei = 1.0; |
|
r = 1.0; |
|
for (int k = 1; k <= 20; k++) { |
|
r = r * k / x; |
|
ei += r; |
|
} |
|
ei = std::exp(x) / x * ei; |
|
} |
|
return ei; |
|
} |
|
|
|
XSF_HOST_DEVICE inline float expi(float x) { return expi(static_cast<double>(x)); } |
|
|
|
std::complex<double> expi(std::complex<double> z) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
std::complex<double> cei; |
|
cei = - exp1(-z); |
|
if (z.imag() > 0.0) { |
|
cei += std::complex<double>(0.0, M_PI); |
|
} else if (z.imag() < 0.0 ) { |
|
cei -= std::complex<double>(0.0, M_PI); |
|
} else { |
|
if (z.real() > 0.0) { |
|
cei += std::complex<double>(0.0, copysign(M_PI, z.imag())); |
|
} |
|
} |
|
return cei; |
|
} |
|
|
|
|
|
XSF_HOST_DEVICE inline std::complex<float> expi(std::complex<float> z) { |
|
return static_cast<std::complex<float>>(expi(static_cast<std::complex<double>>(z))); |
|
} |
|
|
|
namespace detail { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XSF_HOST_DEVICE inline double expint1_factor_cont_frac(double x) { |
|
|
|
|
|
int m = 20 + (int) (80.0 / x); |
|
double t0 = 0.0; |
|
for (int k = m; k > 0; --k) { |
|
t0 = k / (x + k / (1 + t0)); |
|
} |
|
return 1 / (1 + t0); |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XSF_HOST_DEVICE inline double scaled_exp1(double x) { |
|
if (x < 0) { |
|
return std::numeric_limits<double>::quiet_NaN(); |
|
} |
|
|
|
if (x == 0) { |
|
return 0.0; |
|
} |
|
|
|
if (x <= 1) { |
|
|
|
return x * std::exp(x) * exp1(x); |
|
} |
|
|
|
if (x <= 1250) { |
|
|
|
return detail::expint1_factor_cont_frac(x); |
|
} |
|
|
|
|
|
|
|
return 1 + (-1 + (2 + (-6 + (24 - 120 / x) / x) / x) / x) / x; |
|
} |
|
|
|
XSF_HOST_DEVICE inline float scaled_exp1(float x) { return scaled_exp1(static_cast<double>(x)); } |
|
|
|
} |
|
|