#include <primecount-internal.hpp>
#include <generate.hpp>
#include <int128_t.hpp>
#include <stdint.h>
#include <cmath>
#include <limits>
#if defined(HAVE_FLOAT128)
#include <quadmath.h>
#endif
namespace {
using namespace primecount;
long double li(long double x)
{
if (x <= 1)
return 0;
long double gamma = 0.577215664901532860606512090082402431L;
long double sum = 0;
long double inner_sum = 0;
long double factorial = 1;
long double p = -1;
long double q = 0;
long double power2 = 1;
long double logx = std::log(x);
int k = 0;
for (int n = 1; true; n++)
{
p *= -logx;
factorial *= n;
q = factorial * power2;
power2 *= 2;
for (; k <= (n - 1) / 2; k++)
inner_sum += 1.0L / (2 * k + 1);
auto old_sum = sum;
sum += (p / q) * inner_sum;
if (std::abs(sum - old_sum) < std::numeric_limits<long double>::epsilon())
break;
}
return gamma + std::log(logx) + std::sqrt(x) * sum;
}
long double Li(long double x)
{
long double li2 = 1.045163780117492784844588889194613136L;
if (x <= li2)
return 0;
else
return li(x) - li2;
}
long double Li_inverse(long double x)
{
if (x < 2)
return 0;
long double t = x * std::log(x);
long double old_term = std::numeric_limits<long double>::infinity();
while (true)
{
long double term = (Li(t) - x) * std::log(t);
if (std::abs(term) >= std::abs(old_term))
break;
t -= term;
old_term = term;
}
return t;
}
long double Ri(long double x)
{
if (x <= 1)
return 0;
long double sum = 0;
long double old_term = std::numeric_limits<long double>::infinity();
auto terms = (int) (std::log2(x) * 2 + 10);
auto mu = generate_moebius(terms);
for (int n = 1; n < terms; n++)
{
if (mu[n])
{
long double root = std::pow(x, 1.0L / n);
long double term = (li(root) * mu[n]) / n;
if (std::abs(term) >= std::abs(old_term))
break;
sum += term;
old_term = term;
}
}
return sum;
}
long double Ri_inverse(long double x)
{
if (x < 2)
return 0;
long double t = Li_inverse(x);
long double old_term = std::numeric_limits<long double>::infinity();
while (true)
{
long double term = (Ri(t) - x) * std::log(t);
if (std::abs(term) >= std::abs(old_term))
break;
t -= term;
old_term = term;
}
return t;
}
#if defined(HAVE_FLOAT128)
__float128 li(__float128 x)
{
if (x <= 1)
return 0;
__float128 gamma = 0.577215664901532860606512090082402431Q;
__float128 sum = 0;
__float128 inner_sum = 0;
__float128 factorial = 1;
__float128 p = -1;
__float128 q = 0;
__float128 power2 = 1;
__float128 logx = logq(x);
int k = 0;
for (int n = 1; true; n++)
{
p *= -logx;
factorial *= n;
q = factorial * power2;
power2 *= 2;
for (; k <= (n - 1) / 2; k++)
inner_sum += 1.0Q / (2 * k + 1);
auto old_sum = sum;
sum += (p / q) * inner_sum;
if (fabsq(sum - old_sum) < FLT128_EPSILON)
break;
}
return gamma + logq(logx) + sqrtq(x) * sum;
}
__float128 Li(__float128 x)
{
__float128 li2 = 1.045163780117492784844588889194613136Q;
if (x <= li2)
return 0;
else
return li(x) - li2;
}
__float128 Li_inverse(__float128 x)
{
if (x < 2)
return 0;
__float128 t = x * logq(x);
__float128 old_term = FLT128_MAX;
while (true)
{
__float128 term = (Li(t) - x) * logq(t);
if (fabsq(term) >= fabsq(old_term))
break;
t -= term;
old_term = term;
}
return t;
}
__float128 Ri(__float128 x)
{
if (x <= 1)
return 0;
__float128 sum = 0;
__float128 old_term = FLT128_MAX;
auto terms = (int) (log2q(x) * 2 + 10);
auto mu = generate_moebius(terms);
for (int n = 1; n < terms; n++)
{
if (mu[n])
{
__float128 root = powq(x, 1.0Q / n);
__float128 term = (li(root) * mu[n]) / n;
if (fabsq(term) >= fabsq(old_term))
break;
sum += term;
old_term = term;
}
}
return sum;
}
__float128 Ri_inverse(__float128 x)
{
if (x < 2)
return 0;
__float128 t = Li_inverse(x);
__float128 old_term = FLT128_MAX;
while (true)
{
__float128 term = (Ri(t) - x) * logq(t);
if (fabsq(term) >= fabsq(old_term))
break;
t -= term;
old_term = term;
}
return t;
}
#endif
}
namespace primecount {
int64_t Li(int64_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int64_t) ::Li((__float128) x);
#endif
return (int64_t) ::Li((long double) x);
}
int64_t Li_inverse(int64_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int64_t) ::Li_inverse((__float128) x);
#endif
return (int64_t) ::Li_inverse((long double) x);
}
int64_t Ri(int64_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int64_t) ::Ri((__float128) x);
#endif
return (int64_t) ::Ri((long double) x);
}
int64_t Ri_inverse(int64_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int64_t) ::Ri_inverse((__float128) x);
#endif
return (int64_t) ::Ri_inverse((long double) x);
}
#ifdef HAVE_INT128_T
int128_t Li(int128_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int128_t) ::Li((__float128) x);
#endif
return (int128_t) ::Li((long double) x);
}
int128_t Li_inverse(int128_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int128_t) ::Li_inverse((__float128) x);
#endif
return (int128_t) ::Li_inverse((long double) x);
}
int128_t Ri(int128_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int128_t) ::Ri((__float128) x);
#endif
return (int128_t) ::Ri((long double) x);
}
int128_t Ri_inverse(int128_t x)
{
#if defined(HAVE_FLOAT128)
if (x > 1e14)
return (int128_t) ::Ri_inverse((__float128) x);
#endif
return (int128_t) ::Ri_inverse((long double) x);
}
#endif
}