Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
native_exponential_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{
8// Keep the provider evaluation away from its extreme exponent boundary. The
9// final multiply supplies native overflow/subnormal rounding. This also avoids
10// premature overflow in binary128 pow and premature nonzero exp10 underflow.
11template <NativeReal R, class Evaluate> R scaled_decimal_exponential(R x, Evaluate evaluate)
12{
13 if (x > R(numeric_limits<R>::max_exponent / 4) || x < R(numeric_limits<R>::min_exponent / 4))
14 {
15 R half = evaluate(x / 2);
16 return half * half;
17 }
18 return evaluate(x);
19}
20
21template <NativeReal R> struct portable_exponential_math
22{
23 static R exp10(R x)
24 {
25 return scaled_decimal_exponential(x, [](R value) { return std::pow(R(10), value); });
26 }
27
28 static R exp2m1(R x)
29 {
30 if (std::abs(x) <= R(0.5)) return std::expm1(x * log_two<R>);
31 return std::exp2(x) - R(1);
32 }
33
34 static R exp10m1(R x)
35 {
36 if (std::abs(x) <= R(0.5)) return std::expm1(x * std::numbers::ln10_v<R>);
37 return portable_exponential_math::exp10(x) - R(1);
38 }
39
40 template <bool Binary> static R log_base_p1(R x)
41 {
42 constexpr R inverse_log = Binary ? std::numbers::log2e_v<R> : std::numbers::log10e_v<R>;
43 if (std::abs(x) <= R(0.25) || !std::isfinite(x) || x <= R(-1)) return std::log1p(x) * inverse_log;
44 // TwoSum(1,x) retains the part discarded by the rounded addition.
45 // Here the result is bounded away from zero. The omitted quadratic
46 // correction in log1p(low/sum) is O(epsilon^2).
47 R sum = R(1) + x;
48 R part = sum - R(1);
49 R low = (R(1) - (sum - part)) + (x - part);
50 R logarithm = Binary ? std::log2(sum) : std::log10(sum);
51 return std::fma(low / sum, inverse_log, logarithm);
52 }
53
54 static R log2p1(R x) { return log_base_p1<true>(x); }
55 static R log10p1(R x) { return log_base_p1<false>(x); }
56};
57
58template <NativeReal R> struct exponential_math_provider : portable_exponential_math<R>
59{};
60
61#if UNI20_HAS_EXP10_FLOAT || UNI20_HAS_EXP2M1_FLOAT || UNI20_HAS_EXP10M1_FLOAT || UNI20_HAS_LOG2P1_FLOAT || \
62 UNI20_HAS_LOG10P1_FLOAT
63template <> struct exponential_math_provider<float> : portable_exponential_math<float>
64{
65#if UNI20_HAS_EXP10_FLOAT
66 static float exp10(float x)
67 {
68 return scaled_decimal_exponential(x, [](float value) { return ::exp10f(value); });
69 }
70#endif
71#if UNI20_HAS_EXP2M1_FLOAT
72 static float exp2m1(float x) { return ::exp2m1f(x); }
73#endif
74#if UNI20_HAS_EXP10M1_FLOAT
75 static float exp10m1(float x) { return ::exp10m1f(x); }
76#endif
77#if UNI20_HAS_LOG2P1_FLOAT
78 static float log2p1(float x) { return ::log2p1f(x); }
79#endif
80#if UNI20_HAS_LOG10P1_FLOAT
81 static float log10p1(float x) { return ::log10p1f(x); }
82#endif
83};
84#endif
85
86#if UNI20_HAS_EXP10_DOUBLE || UNI20_HAS_EXP2M1_DOUBLE || UNI20_HAS_EXP10M1_DOUBLE || UNI20_HAS_LOG2P1_DOUBLE || \
87 UNI20_HAS_LOG10P1_DOUBLE
88template <> struct exponential_math_provider<double> : portable_exponential_math<double>
89{
90#if UNI20_HAS_EXP10_DOUBLE
91 static double exp10(double x)
92 {
93 return scaled_decimal_exponential(x, [](double value) { return ::exp10(value); });
94 }
95#endif
96#if UNI20_HAS_EXP2M1_DOUBLE
97 static double exp2m1(double x) { return ::exp2m1(x); }
98#endif
99#if UNI20_HAS_EXP10M1_DOUBLE
100 static double exp10m1(double x) { return ::exp10m1(x); }
101#endif
102#if UNI20_HAS_LOG2P1_DOUBLE
103 static double log2p1(double x) { return ::log2p1(x); }
104#endif
105#if UNI20_HAS_LOG10P1_DOUBLE
106 static double log10p1(double x) { return ::log10p1(x); }
107#endif
108};
109#endif
110
111#if UNI20_HAS_EXP10_LONG_DOUBLE || UNI20_HAS_EXP2M1_LONG_DOUBLE || UNI20_HAS_EXP10M1_LONG_DOUBLE || \
112 UNI20_HAS_LOG2P1_LONG_DOUBLE || UNI20_HAS_LOG10P1_LONG_DOUBLE
113template <> struct exponential_math_provider<long double> : portable_exponential_math<long double>
114{
115#if UNI20_HAS_EXP10_LONG_DOUBLE
116 static long double exp10(long double x)
117 {
118 return scaled_decimal_exponential(x, [](long double value) { return ::exp10l(value); });
119 }
120#endif
121#if UNI20_HAS_EXP2M1_LONG_DOUBLE
122 static long double exp2m1(long double x) { return ::exp2m1l(x); }
123#endif
124#if UNI20_HAS_EXP10M1_LONG_DOUBLE
125 static long double exp10m1(long double x) { return ::exp10m1l(x); }
126#endif
127#if UNI20_HAS_LOG2P1_LONG_DOUBLE
128 static long double log2p1(long double x) { return ::log2p1l(x); }
129#endif
130#if UNI20_HAS_LOG10P1_LONG_DOUBLE
131 static long double log10p1(long double x) { return ::log10p1l(x); }
132#endif
133};
134#endif
135
136#if UNI20_HAS_FLOAT128 && (UNI20_HAS_EXP10_FLOAT128 || UNI20_HAS_EXP2M1_FLOAT128 || UNI20_HAS_EXP10M1_FLOAT128 || \
137 UNI20_HAS_LOG2P1_FLOAT128 || UNI20_HAS_LOG10P1_FLOAT128)
138template <> struct exponential_math_provider<float128> : portable_exponential_math<float128>
139{
140#if UNI20_HAS_EXP10_FLOAT128
141 static float128 exp10(float128 x)
142 {
143 return scaled_decimal_exponential(x, [](float128 value) { return ::exp10f128(value); });
144 }
145#endif
146#if UNI20_HAS_EXP2M1_FLOAT128
147 static float128 exp2m1(float128 x) { return ::exp2m1f128(x); }
148#endif
149#if UNI20_HAS_EXP10M1_FLOAT128
150 static float128 exp10m1(float128 x) { return ::exp10m1f128(x); }
151#endif
152#if UNI20_HAS_LOG2P1_FLOAT128
153 static float128 log2p1(float128 x) { return ::log2p1f128(x); }
154#endif
155#if UNI20_HAS_LOG10P1_FLOAT128
156 static float128 log10p1(float128 x) { return ::log10p1f128(x); }
157#endif
158};
159#endif
160
161template <NativeReal R> R exp10(R x) { return exponential_math_provider<R>::exp10(x); }
162template <NativeReal R> R exp2m1(R x) { return exponential_math_provider<R>::exp2m1(x); }
163template <NativeReal R> R exp10m1(R x) { return exponential_math_provider<R>::exp10m1(x); }
164template <NativeReal R> R log2p1(R x) { return exponential_math_provider<R>::log2p1(x); }
165template <NativeReal R> R log10p1(R x) { return exponential_math_provider<R>::log10p1(x); }
166} // namespace uni20::detail::native_math
locale_t value
Definition data_table.cpp:49
Definition qnum.hpp:403
constexpr detail::scalar_math::log2p1_fn log2p1
Base-two logarithm of one plus x, without rounding the sum first.
Definition math.hpp:636
constexpr detail::scalar_math::log10p1_fn log10p1
Base-ten logarithm of one plus x, without rounding the sum first.
Definition math.hpp:638
constexpr detail::scalar_math::exp10m1_fn exp10m1
Ten to the power x minus one, using the cancellation-safe provider.
Definition math.hpp:634
constexpr detail::scalar_math::exp2m1_fn exp2m1
Two to the power x minus one, using the cancellation-safe provider.
Definition math.hpp:632
constexpr detail::scalar_math::exp10_fn exp10
Base-ten exponential.
Definition math.hpp:630
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
mpreal log10(mpreal const &x)
Base-ten logarithm; retain input precision or a supported exact result.
Definition mpreal.hpp:736