7namespace uni20::detail::native_math::airy_detail
9template <NativeReal R> Expansion<R> constant(std::uint16_t
const* a)
13 for (
int k = 0; k < n; ++k)
14 r = r + Expansion<R>(std::ldexp(R(a[k]), -16 * (k + 1)));
17template <NativeReal R> Expansion<R> wide_sqrt(R x)
19 using E = Expansion<R>;
21 for (
int k = 0; k < 3; ++k)
22 s = s + (E(x) - s * s) / (E(2) * s);
25template <NativeReal R> Expansion<R> wide_log(Expansion<R> x)
27 using E = Expansion<R>;
30 R m = std::frexp(x.high(), &n);
33 E t = (x - E(1)) / (x + E(1)),
square = t * t, term = t,
sum = t;
34 R eps = std::ldexp(R(1), -4 * L::digits() + 8);
35 for (
int k = 1; k < 4 * L::digits(); ++k)
38 E v = term / R(2 * k + 1);
40 if (std::abs(v.high()) < eps * std::abs(
sum.high()))
break;
42 return E(2) *
sum + E(R(n)) * constant<R>(log_two_bits);
44template <NativeReal R> R wide_exp(Expansion<R> x)
46 using E = Expansion<R>;
48 E ln2 = constant<R>(log_two_bits);
49 int n = int(std::nearbyint(x.high() / ln2.high()));
50 E r = x - E(R(n)) * ln2,
sum(1), term(1);
51 R eps = std::ldexp(R(1), -4 * L::digits() + 8);
52 for (
int k = 1; k < 4 * L::digits(); ++k)
54 term = term * r / R(k);
56 if (std::abs(term.high()) < eps)
break;
58 if (n < L::min_exponent)
60 constexpr int d = L::min_exponent - L::digits();
61 E units =
sum.scaled(n - d);
62 R q = std::floor(units.high());
69 E half = rem - E(R(.5));
70 if (half.high() > 0 || (half.high() == 0 && std::fmod(q, R(2)) != 0)) q += 1;
71 return std::ldexp(q, d);
73 return std::ldexp(
sum.rounded(), n);
77template <NativeReal R> R guarded_positive(R x)
79 using E = Expansion<R>;
81 E z = E(2) * E(x) * wide_sqrt(x) / R(3), inv = E(1) / z, term(1),
sum(1);
82 R eps = std::ldexp(R(1), -4 * L::digits() + 8);
84 for (
int k = 1; k < 4 * L::digits(); ++k)
86 term = term * E(R((6 * k - 5) * (6 * k - 1))) * inv / R(72 * k);
87 sum =
sum + (k % 2 ? -term : term);
88 if (term.high() < eps)
94 if (!done)
return L::quiet_NaN();
95 E logpi = E(1) + constant<R>(log_pi_fraction_bits);
96 return wide_exp(-z - logpi / R(2) - wide_log(E(x)) / R(4) - constant<R>(log_two_bits) + wide_log(
sum));
100template <NativeReal R> R central(R x)
103 using E = Expansion<R>;
104 E z = E(x) * E(x) * E(x), f(1), g(1), tf(1), tg(1);
105 R eps = std::ldexp(R(1), -4 * L::digits() + 8);
106 for (
int k = 1; k < 4 * L::digits() + 64; ++k)
108 tf = tf * z / R((3 * k) * (3 * k - 1));
109 tg = tg * z / R((3 * k) * (3 * k + 1));
112 if (std::abs(tf.high()) < eps * std::abs(f.high()) && std::abs(tg.high()) < eps * std::abs(g.high()))
113 return (constant<R>(ai_zero_bits) * f - constant<R>(ai_prime_zero_bits) * E(x) * g).rounded();
115 return L::quiet_NaN();
119template <NativeReal R> R asymptotic(R x)
122 bool positive = x > 0;
123 R v = std::abs(x), inverse = (R(1.5) / v) / std::sqrt(v), term = 1, even = 1, odd = 0, previous = 1;
125 for (
int k = 1; k < 4 * L::digits() + 64; ++k)
127 term *= R((6 * k - 5) * (6 * k - 1)) / R(72 * k) * inverse;
128 if (term > previous)
return L::quiet_NaN();
130 even += k % 2 ? -term : term;
132 odd += (k / 2) % 2 ? -term : term;
134 even += (k / 2) % 2 ? -term : term;
135 if (term < L::epsilon() / 32)
142 if (!done)
return L::quiet_NaN();
143 R amplitude = 1 / (std::sqrt(uni20::pi<R>) * std::sqrt(std::sqrt(v)));
146 R
zeta = (R(2) / 3) * v * std::sqrt(v);
148 if (std::abs(estimate - std::log(L::denorm_min())) < 8)
return guarded_positive(v);
149 R half = std::exp(-zeta / 2);
150 return half * (half * (amplitude * (even / 2)));
152 auto [s,
c] = phase(v);
153 return amplitude * std::fma(s, even, -
c * odd);
155template <NativeReal R> R airy(R x)
158 if (std::isnan(x))
return x;
159 if (std::isinf(x))
return 0;
160 constexpr int join = L::digits() <= 24 ? 8 : L::digits() <= 53 ? 12 : L::digits() <= 64 ? 14 : 20;
161 if (std::abs(x) <= join)
return central(x);
162 if (x > R(2 * (L::digits() - L::min_exponent)))
return 0;
163 return asymptotic(x);
167namespace uni20::detail::native_math
171template <NativeReal R> R
airy_ai(R x) {
return airy_detail::airy(x); }
AsyncTask square(ReadBuffer< int > in, WriteBuffer< int > out)
Definition async_tbb_reduction_example.cpp:39
constexpr detail::scalar_math::zeta_fn zeta
Real Riemann zeta with native Euler-Maclaurin evaluation and reflection.
Definition math.hpp:601
constexpr detail::scalar_math::airy_ai_fn airy_ai
Real Airy Ai; native inputs retain their precision and full negative-axis phase.
Definition math.hpp:620
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
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16