14#ifndef dealii_fast_transcendental_h
15#define dealii_fast_transcendental_h
30#elif defined(__ARM_NEON)
32#elif defined(__x86_64__)
33# include <x86intrin.h>
58 template <
int degree,
typename Number>
60 []() -> std::array<Number, degree + 1> {
61 static_assert(degree > 2 && degree < 12,
62 "Unsupported polynomial degree for exp_pol_coeff.");
63 return std::array<Number, degree + 1>{};
66 template <
typename Number>
68 {1.8809206555322363e-04,
69 3.0316116404944521e-01,
70 -2.2412622972531135e-01,
71 -7.9019886953785187e-02}};
73 template <
typename Number>
75 {-7.2868375805796964e-06,
76 3.0706874220004554e-01,
77 -2.4171033150558635e-01,
78 -5.1666839694436362e-02,
79 -1.3676523629674565e-02}};
81 template <
typename Number>
83 {2.3053723876408911e-07,
84 3.0684322094757277e-01,
85 -2.4013168272249241e-01,
86 -5.5876569798473615e-02,
87 -8.9405772567122607e-03,
88 -1.8943785491846432e-03}};
90 template <
typename Number>
92 {-6.1646222105268035e-09,
93 3.0685316242622318e-01,
94 -2.4023109751048086e-01,
95 -5.5478910644035311e-02,
96 -9.6861881733345725e-03,
97 -1.2382409419015978e-03,
98 -2.1871253576104385e-04}};
100 template <
typename Number>
102 {1.4276280848886066e-10,
103 3.0685280921264796e-01,
104 -2.4022632912712596e-01,
105 -5.5505401662914296e-02,
106 -9.6133378710895074e-03,
107 -1.3431453773612783e-03,
108 -1.4294822119902167e-04,
109 -2.1646947017882258e-05}};
111 template <
typename Number>
113 {-2.9146986289710858e-12,
114 3.0685281970141953e-01,
115 -2.4022651268062989e-01,
116 -5.5504055603868258e-02,
117 -9.6183855925465120e-03,
118 -1.3326461166925901e-03,
119 -1.5519735866800178e-04,
120 -1.4147475092332136e-05,
121 -1.8748679813608566e-06}};
123 template <
typename Number>
125 {5.4337475594757437e-14,
126 3.0685281943421089e-01,
127 -2.4022650680203564e-01,
128 -5.5504110470759059e-02,
129 -9.6181181164443925e-03,
130 -1.3333950497836748e-03,
131 -1.5394913684739714e-04,
132 -1.5370223000068715e-05,
133 -1.2252831550509094e-06,
134 -1.4435218373241001e-07}};
136 template <
typename Number>
138 {7.6072080297756739e-12,
139 3.0685281862960340e-01,
140 -2.4022648563631835e-01,
141 -5.5504349821691862e-02,
142 -9.6166785909533817e-03,
143 -1.3384970969245304e-03,
144 -1.4276337493295606e-04,
145 -3.0711077326624553e-05,
146 1.1584454591775664e-05,
147 -6.0984990187293866e-06,
148 1.1810109241254786e-06}};
150 template <
typename Number>
152 {3.6083394569535254e-13,
153 3.0685281939395403e-01,
154 -2.4022650549710606e-01,
155 -5.5504128716495800e-02,
156 -9.6179813320517119e-03,
157 -1.3340079120703319e-03,
158 -1.5221190054222076e-04,
159 -1.8563222423500779e-05,
160 2.5694826992914108e-06,
161 -2.9577981133179920e-06,
162 1.1827521620524028e-06,
163 -2.1525063398151332e-07}};
168 template <
typename Number>
178 template <
typename Number>
179 inline constexpr Number
exp_coeff_b = numbers::signaling_nan<Number>();
190 template <
typename Number>
191 inline constexpr Number
max_exponent = numbers::signaling_nan<Number>();
202 template <
typename Number>
224#if DEAL_II_VECTORIZATION_WIDTH_IN_BITS >= 512 && defined(__AVX512F__)
229 const __m512i integer = _mm512_cvtpd_epi64(in.
data);
230 out.data = _mm512_castsi512_pd(integer);
238 const __m512i integer = _mm512_cvtps_epi32(in.
data);
239 out.data = _mm512_castsi512_ps(integer);
244#if DEAL_II_VECTORIZATION_WIDTH_IN_BITS >= 256 && defined(__AVX__)
249 int64_t int_values[4];
250 for (
int i = 0; i < 4; i++)
252 int_values[i] =
static_cast<int64_t
>(in[i]);
254 out.
data = _mm256_castsi256_pd(
255 _mm256_loadu_si256(
reinterpret_cast<__m256i *
>(int_values)));
263 int32_t int_values[8];
264 for (
int i = 0; i < 8; i++)
266 int_values[i] =
static_cast<int32_t
>(in[i]);
268 out.
data = _mm256_castsi256_ps(
269 _mm256_loadu_si256(
reinterpret_cast<__m256i *
>(int_values)));
274#if DEAL_II_VECTORIZATION_WIDTH_IN_BITS >= 128 && defined(__SSE2__)
279 int64_t int_values[2];
280 for (
int i = 0; i < 2; i++)
282 int_values[i] =
static_cast<int64_t
>(in[i]);
284 out.
data = _mm_castsi128_pd(
285 _mm_loadu_si128(
reinterpret_cast<__m128i *
>(int_values)));
293 int32_t int_values[4];
294 for (
int i = 0; i < 4; i++)
296 int_values[i] =
static_cast<int32_t
>(in[i]);
298 out.
data = _mm_castsi128_ps(
299 _mm_loadu_si128(
reinterpret_cast<__m128i *
>(int_values)));
304#if DEAL_II_VECTORIZATION_WIDTH_IN_BITS >= 128 && defined(__ARM_NEON)
309 const int64x2_t int_values = vcvtq_s64_f64(in.
data);
310 out.
data = vreinterpretq_f64_s64(int_values);
318 const int32x4_t int_values = vcvtq_s32_f32(in.
data);
319 out.
data = vreinterpretq_f32_s32(int_values);
324 template <
typename number>
329 const auto result =
static_cast<
330 std::conditional_t<std::is_same_v<number, double>, int64_t, int32_t
>>(
332 std::memcpy(&out.
data, &result,
sizeof(out.
data));
354 template <
int degree,
typename CoeffsType,
typename ValueType>
359 ValueType result = c.back();
360 for (
int i = c.size() - 2; i >= 0; --i)
361 result = c[i] + x * result;
384 template <
int degree,
typename CoeffsType,
typename ValueType>
389 constexpr int n_precomputed_x_powers = degree / 2;
390 std::array<ValueType, n_precomputed_x_powers> x_powers;
392 for (
unsigned i = 1; i < n_precomputed_x_powers; ++i)
393 x_powers[i] = x_powers[i - 1] * x_powers[0];
396 t1 = (c[0] + c[1] * x);
398 for (
unsigned i = 2; i < degree; i += 2)
400 t2 = (c[i] + c[i + 1] * x);
401 t1 += t2 * x_powers[(i - 2) / 2];
404 if constexpr (degree % 2 == 0)
405 t1 += c.back() * x_powers.back();
507 template <
int degree,
509 bool ensure_correct_treatment_of_zero =
true,
510 bool ensure_correct_treatment_of_infinity =
true,
516 if constexpr (std::is_floating_point_v<Number>)
520 ensure_correct_treatment_of_zero,
521 ensure_correct_treatment_of_infinity,
522 polynomial_evaluation_scheme>(
528 using floating_type =
typename Number::value_type;
531 std::is_same_v<floating_type, double> ||
532 std::is_same_v<floating_type, float>,
533 "The fast transcendental approximation of the exp() function only supports the fundamental types float and double.");
537 Number fractional_exponent = r - r.get_floor();
539 if constexpr (polynomial_evaluation_scheme ==
541 r -= internal::horner_scheme<degree>(
542 internal::exp_pol_coeff<degree, floating_type>,
543 fractional_exponent);
544 else if constexpr (polynomial_evaluation_scheme ==
546 r -= internal::estrin_scheme<degree>(
547 internal::exp_pol_coeff<degree, floating_type>,
548 fractional_exponent);
553 "The provided scheme for the evaluation of the correction function is not supported!");
555 r = internal::exp_coeff_a<floating_type> * r +
556 internal::exp_coeff_b<floating_type>;
561 if constexpr (ensure_correct_treatment_of_zero)
565 r = compare_and_apply_mask<SIMDComparison::less_than>(
567 Number(-internal::exp_max_abs_x<floating_type>),
571 if constexpr (ensure_correct_treatment_of_infinity)
573 r = compare_and_apply_mask<SIMDComparison::greater_than>(
575 Number(internal::exp_max_abs_x<floating_type>),
576 Number(internal::max_exponent<floating_type>),
#define DEAL_II_ALWAYS_INLINE
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
constexpr std::array< Number, 12 > exp_pol_coeff< 11, Number >
constexpr std::array< Number, 5 > exp_pol_coeff< 4, Number >
constexpr double exp_max_abs_x< double >
constexpr Number max_exponent
constexpr Number exp_coeff_a
constexpr float exp_coeff_a< float >
constexpr std::array< Number, 4 > exp_pol_coeff< 3, Number >
constexpr std::array< Number, 10 > exp_pol_coeff< 9, Number >
constexpr Number exp_coeff_b
constexpr std::array< Number, 11 > exp_pol_coeff< 10, Number >
constexpr float max_exponent< float >
constexpr std::array< Number, 8 > exp_pol_coeff< 7, Number >
constexpr std::array< Number, 7 > exp_pol_coeff< 6, Number >
constexpr float exp_coeff_b< float >
constexpr std::array< Number, 6 > exp_pol_coeff< 5, Number >
VectorizedArray< number, 1 > type_cast(const VectorizedArray< number, 1 > &in)
constexpr Number exp_max_abs_x
constexpr double max_exponent< double >
constexpr float exp_max_abs_x< float >
ValueType estrin_scheme(const std::array< CoeffsType, degree+1 > &c, const ValueType &x)
constexpr std::array< Number, 9 > exp_pol_coeff< 8, Number >
constexpr std::array< Number, degree+1 > exp_pol_coeff
ValueType horner_scheme(const std::array< CoeffsType, degree+1 > &c, const ValueType &x)
constexpr double exp_coeff_b< double >
constexpr double exp_coeff_a< double >