Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
native_expint_math.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "native_math.hpp"
5
6namespace uni20::detail::native_math
7{
8template <NativeReal R> R expint_series(R x)
9{
10 using L = numeric_limits<R>;
11 R sum = euler_gamma<R>, low = 0;
12 auto add = [&](R value) {
13 R next = sum + value;
14 low += std::abs(sum) >= std::abs(value) ? (sum - next) + value : (value - next) + sum;
15 sum = next;
16 };
17 add(std::log(std::abs(x)));
18 R power = R(1);
19 for (int k = 1; k <= 8 * L::digits() + 64; ++k)
20 {
21 power *= x / R(k);
22 R term = power / R(k);
23 add(term);
24 if (R(k) >= 2 * std::abs(x) && std::abs(term) <= L::epsilon() * std::max(R(1), std::abs(sum)) / 16)
25 return sum + low;
26 }
27 return L::quiet_NaN();
28}
29
30// Positive E1 continued fraction, divided by exp(-x). Neighboring positive
31// truncations bracket the exact value; backwards evaluation avoids products
32// of successive forward-update factors and cancellation in denominators.
33template <NativeReal R> R scaled_e1(R x)
34{
35 using L = numeric_limits<R>;
36 for (int depth = 16; depth <= 16 * L::digits(); depth *= 2)
37 {
38 R lo = R(depth) / (R(1) + R(depth) / x), hi = R(depth);
39 for (int k = depth - 1; k >= 1; --k)
40 {
41 lo = R(k) / (R(1) + R(k) / (x + lo));
42 hi = R(k) / (R(1) + R(k) / (x + hi));
43 }
44 lo = R(1) / (x + lo);
45 hi = R(1) / (x + hi);
46 if (std::abs(lo - hi) <= 4 * L::epsilon() * lo) return (lo + hi) / 2;
47 }
48 return L::quiet_NaN();
49}
50
51template <NativeReal R> R scaled_positive_ei(R x)
52{
53 using L = numeric_limits<R>;
54 R sum = 1, low = 0, term = 1;
55 for (int k = 1; k <= L::digits(); ++k)
56 {
57 term *= R(k) / x;
58 R next = sum + term;
59 low += (sum - next) + term;
60 sum = next;
61 // Here x>=2*digits and k<=digits, so the next term is smaller.
62 // The DLMF remainder factor is <k+4, giving truncation <eps*sum/2.
63 if (term <= L::epsilon() * sum / R(4 * (k + 2))) return (sum + low) / x;
64 }
65 return L::quiet_NaN();
66}
67
68template <NativeReal R> R expint(R x)
69{
70 using L = numeric_limits<R>;
71 if (std::isnan(x)) return x;
72 if (x == 0) return -L::infinity();
73 // These conservative cutoffs are far beyond final native range boundaries.
74 if (x > R(2 * L::max_exponent)) return L::infinity();
75 if (x < R(2 * (L::min_exponent - L::digits()))) return -R(0);
76 if (x >= R(-1) && x < R(2 * L::digits())) return native_math::expint_series(x);
77 R factor = x < 0 ? -native_math::scaled_e1(-x) : native_math::scaled_positive_ei(x);
78 R half = std::exp(x / 2);
79 return half * (half * factor);
80}
81} // namespace uni20::detail::native_math
locale_t value
Definition data_table.cpp:49
constexpr detail::scalar_math::expint_fn expint
Real principal-value exponential integral Ei.
Definition math.hpp:605
void sum(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< InputTensor > const &input)
Schedule a full sum into an explicit async scalar tensor.
Definition linalg/async/reductions.hpp:309
int add(int a, int b)
Definition dummy.cpp:6