|
Go to the documentation of this file.
37 constexpr double inf = std::numeric_limits<double>::infinity();
38 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
39 constexpr double PI = 3.1415926535897932;
41 constexpr bool is_even(int64_t n) noexcept { return n % 2 == 0; }
43 constexpr bool is_finite( const std::complex<double>& z) noexcept
45 return std::isfinite(std::real(z)) && std::isfinite(std::imag(z));
49 std::complex<double> clog( const std::complex<double>& z) noexcept
51 if (std::imag(z) == 0.0 && std::real(z) > 0.0) {
52 return { std::log(std::real(z)), 0.0 };
53 } else if (std::imag(z) == 0.0) {
54 return { std::log(-std::real(z)), PI };
56 return { std::log(std::hypot(std::real(z), std::imag(z))), std::arg(z) };
61 std::complex<double> Li_series(int64_t n, const std::complex<double>& z) noexcept
63 std::complex<double> sum(0.0, 0.0), sum_old(0.0, 0.0), p = z;
70 p *= z*std::pow(k/(1.0 + k), n);
72 } while ( sum != sum_old &&
73 k < std::numeric_limits<int64_t>::max() - 2);
79 std::complex<double> Li_unity_pos(int64_t n, const std::complex<double>& z) noexcept
81 const std::complex<double> lnz = clog(z);
82 const std::complex<double> lnz2 = lnz*lnz;
83 std::complex<double> sum( zeta(n), 0.0), p(1.0, 0.0);
85 for (int64_t j = 1; j < n - 1; ++j) {
86 p *= lnz/ static_cast<double>(j);
90 p *= lnz/ static_cast<double>(n - 1);
93 p *= lnz/ static_cast<double>(n);
96 p *= lnz/ static_cast<double>(n + 1);
99 for (int64_t j = (n + 3); j < std::numeric_limits<int64_t>::max() - 2; j += 2) {
100 p *= lnz2/ static_cast<double>((j - 1)*j);
101 const auto old_sum = sum;
103 if ( sum == old_sum) { break; }
110 std::complex<double> stable_pow( const std::complex<double>& z, int64_t n) noexcept
112 if (std::imag(z) == 0) {
113 return { std::pow(std::real(z), n), 0.0 };
114 } else if (std::real(z) == 0) {
115 const double p = std::pow(std::imag(z), n);
118 } else if (n % 2 == 0) {
120 } else if ((n - 1) % 4 == 0) {
125 return std::pow(z, n);
129 std::complex<double> Li_unity_neg(int64_t n, const std::complex<double>& z) noexcept
131 const std::complex<double> lnz = clog(z);
132 const std::complex<double> lnz2 = lnz*lnz;
133 std::complex<double> sum = std::tgamma(1 - n)* stable_pow(-lnz, n - 1);
134 std::complex<double> lnzk, sum_old, term;
153 } while ( sum != sum_old);
159 std::complex<double> Li_rest(int64_t n, const std::complex<double>& z) noexcept
161 const std::complex<double> lnz = clog(-z);
162 const std::complex<double> lnz2 = lnz*lnz;
163 const int64_t kmax = is_even(n) ? n/2 : (n - 1)/2;
164 std::complex<double> p = is_even(n) ? 1.0 : lnz;
165 std::complex<double> sum(0.0, 0.0), old_sum;
167 for (int64_t k = kmax; k != 0; --k) {
168 const double ifac = inv_fac(n - 2*k);
169 if (ifac == 0) { return 2.0* sum; }
172 if ( sum == old_sum) { break; }
191std::complex<double> Li(int64_t n, const std::complex<double>& z) noexcept
193 if (std::isnan(std::real(z)) || std::isnan(std::imag(z))) {
195 } else if (std::isinf(std::real(z)) || std::isinf(std::imag(z))) {
197 } else if (z == 0.0) {
199 } else if (z == 1.0) {
203 return { zeta(n), std::imag(z)};
204 } else if (z == -1.0) {
205 return { neg_eta(n), std::imag(z)};
208 const double nz = std::norm(z);
209 const double nl = std::norm(clog(z));
210 if (4*PI*PI*nz < nl) {
211 return Li_series(n, z);
212 } else if (nl < 0.512*0.512*4*PI*PI) {
213 return Li_unity_neg(n, z);
215 const auto sqrtz = std::sqrt(z);
216 return std::exp2(n - 1)*( Li(n, sqrtz) + Li(n, -sqrtz));
217 } else if (n == -1) {
218 return z/((1.0 - z)*(1.0 - z));
222 return -clog(1.0 - z);
233 } else if (std::norm(z) <= 0.75*0.75) {
234 return Li_series(n, z);
235 } else if (std::norm(z) >= 1.4*1.4) {
236 const double sgn = is_even(n) ? -1.0 : 1.0;
237 return sgn*Li_series(n, 1.0/z) + Li_rest(n, z);
239 return Li_unity_pos(n, z);
std::complex< double > Li_series(int64_t n, const std::complex< double > &z) noexcept
std::complex< double > clog(const std::complex< double > &z) noexcept complex logarithm, converts -0.0 to 0.0
std::complex< double > stable_pow(const std::complex< double > &z, int64_t n) noexcept returns z^n, treating Re(z) == 0 and Im(z) == 0 in a stable way
std::complex< double > Li_unity_neg(int64_t n, const std::complex< double > &z) noexcept Series expansion of Li_n(z) around z ~ 1, n < 0.
std::complex< double > Li_rest(int64_t n, const std::complex< double > &z) noexcept returns remainder from inversion formula
std::complex< double > Li_unity_pos(int64_t n, const std::complex< double > &z) noexcept Series expansion of Li_n(z) around z ~ 1, n > 0.
double neg_eta(int64_t n) noexcept negative Dirichlet eta function
std::complex< double > Li(int64_t n, const std::complex< double > &z) noexcept Complex polylogarithm .
double zeta(int64_t n) noexcept Riemann zeta function for integer arguments.
double Li4(double x) noexcept Real 4-th order polylogarithm .
float Li2(float x) noexcept Real dilogarithm .
std::complex< double > Li5(const std::complex< double > &z) noexcept Complex polylogarithm .
bool is_finite(const gsl_vector *x) Returns true if GSL vector contains only finite elements, false otherwise.
double Li3(double x) noexcept Real trilogarithm .
double harmonic(int64_t n) noexcept harmonic number n
double inv_fac(int64_t n) noexcept negative Dirichlet eta function
std::complex< double > Li6(const std::complex< double > &z) noexcept Complex polylogarithm .
auto sum(Idx ini, Idx fin, Function f) -> decltype(EvalEigenXpr< Idx >(ini, f))
|