Eigen  5.0.1
 
Loading...
Searching...
No Matches
GenericPacketMathFunctions.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2007 Julien Pommier
5// Copyright (C) 2014 Pedro Gonnet (pedro.gonnet@gmail.com)
6// Copyright (C) 2009-2019 Gael Guennebaud <gael.guennebaud@inria.fr>
7// Copyright (C) 2018-2025 Rasmus Munk Larsen <rmlarsen@gmail.com>
8//
9// This Source Code Form is subject to the terms of the Mozilla
10// Public License v. 2.0. If a copy of the MPL was not distributed
11// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
12// SPDX-License-Identifier: MPL-2.0
13
14/* The exp and log functions of this file initially come from
15 * Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/
16 */
17
18#ifndef EIGEN_ARCH_GENERIC_PACKET_MATH_FUNCTIONS_H
19#define EIGEN_ARCH_GENERIC_PACKET_MATH_FUNCTIONS_H
20
21// IWYU pragma: private
22#include "../../InternalHeaderCheck.h"
23#include "GenericPacketMathPolynomials.h"
24#include "GenericPacketMathFrexpLdexp.h"
25#include "GenericPacketMathDoubleWord.h"
26
27namespace Eigen {
28namespace internal {
29
30//----------------------------------------------------------------------
31// Exponential and Logarithmic Functions
32//----------------------------------------------------------------------
33
34// Core range reduction and polynomial evaluation for float logarithm.
35//
36// Given a positive float value v (may be denormal), decomposes it as
37// v = 2^e * (1+f) with f in [sqrt(0.5)-1, sqrt(2)-1], then evaluates
38// log(1+f) ≈ f + f^2 * P(f) using a degree-7 minimax polynomial.
39//
40// Returns the approximation of log(v_mantissa) in log_mantissa and the
41// integer exponent in e. The caller combines these as appropriate
42// (e.g. e*ln2 + log_mantissa for natural log, or log_mantissa*log2e + e
43// for log2).
44//
45// Range reduction uses integer bit manipulation (musl-inspired) instead of the
46// heavier pfrexp_generic, saving ~12 ops. The minimax polynomial was found via
47// Sollya's fpminimax, giving faithfully-rounded results (max 1 ULP for log).
48template <typename Packet>
49EIGEN_STRONG_INLINE void plog_core_float(const Packet v, Packet& log_mantissa, Packet& e) {
50 using PacketI = typename unpacket_traits<Packet>::integer_packet;
51
52 const PacketI cst_min_normal = pset1<PacketI>(0x00800000);
53 const PacketI cst_mant_mask = pset1<PacketI>(0x007fffff);
54 // Adding this offset to the integer representation biases the exponent so
55 // that values near 1 (0x3f800000) map to exponent 0, and values below
56 // sqrt(0.5) get folded into the previous exponent. The magic constant is
57 // 0x3f800000 - 0x3f3504f3 = 0x004afb0d, where 0x3f3504f3 ≈ sqrt(0.5).
58 const PacketI cst_sqrt_half_offset = pset1<PacketI>(0x004afb0d);
59 const PacketI cst_exp_bias = pset1<PacketI>(0x7f); // 127
60 const PacketI cst_half_mant = pset1<PacketI>(0x3f3504f3); // sqrt(0.5)
61
62 // Normalize denormals by multiplying by 2^23.
63 PacketI vi = preinterpret<PacketI>(v);
64 PacketI is_denormal = pcmp_lt(vi, cst_min_normal);
65 Packet v_normalized = pmul(v, pset1<Packet>(8388608.0f)); // 2^23
66 vi = pselect(is_denormal, preinterpret<PacketI>(v_normalized), vi);
67 // Denormal exponent adjustment: subtract 23 from exponent.
68 PacketI denorm_adj = pand(is_denormal, pset1<PacketI>(23));
69
70 // Combined range reduction: bias integer representation so that exponent
71 // extraction automatically shifts mantissa to [sqrt(0.5), sqrt(2)).
72 PacketI vi_biased = padd(vi, cst_sqrt_half_offset);
73 // Extract exponent as integer, subtract bias and denormal adjustment.
74 PacketI e_int = psub(psub(plogical_shift_right<23>(vi_biased), cst_exp_bias), denorm_adj);
75 e = pcast<PacketI, Packet>(e_int);
76 // Reconstruct mantissa in [sqrt(0.5), sqrt(2)). The integer addition of the
77 // masked mantissa with 0x3f3504f3 (sqrt(0.5)) naturally produces carry into
78 // the exponent field, yielding values in [sqrt(0.5), 1) or [1, sqrt(2)).
79 // Then subtract 1 to center on 0 → f in [sqrt(0.5)-1, sqrt(2)-1].
80 Packet f = psub(preinterpret<Packet>(padd(pand(vi_biased, cst_mant_mask), cst_half_mant)), pset1<Packet>(1.0f));
81
82 // Minimax degree-7 polynomial for g(f) = (log(1+f) - f) / f^2 on
83 // [sqrt(0.5)-1, sqrt(2)-1], so log(1+f) ≈ f + f^2 * P(f).
84 // Generated by Sollya: fpminimax(g, 7, [|single...|], [lo;hi])
85 // Mathematical approximation error: max |log(1+f) - (f + f^2*P(f))| < 2.04e-8.
86 // Coefficients stored in reverse order for ppolevl (highest degree first).
87 constexpr float coeffs[] = {
88 8.8758550584316254e-02f, // c7 (x^7)
89 -1.4199858903884888e-01f, // c6 (x^6)
90 1.4824025332927704e-01f, // c5 (x^5)
91 -1.6583317518234253e-01f, // c4 (x^4)
92 1.9972395896911621e-01f, // c3 (x^3)
93 -2.5001299381256104e-01f, // c2 (x^2)
94 3.3333668112754822e-01f, // c1 (x^1)
95 -4.9999997019767761e-01f, // c0 (x^0)
96 };
97
98 // Evaluate P(f) via Horner's method, then log(1+f) ≈ f + f^2 * P(f).
99 Packet f2 = pmul(f, f);
100 Packet p = ppolevl<Packet, 7>::run(f, coeffs);
101 log_mantissa = pmadd(p, f2, f);
102}
103
104// Natural or base-2 logarithm for float packets.
105//
106// Computes log(x) as e*C + log(m), where x = 2^e * m with m in [sqrt(1/2), sqrt(2))
107// and C = ln(2) for natural log, C = 1 for log2.
108template <typename Packet, bool base2>
109EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog_impl_float(const Packet _x) {
110 Packet log_mantissa, e;
111 plog_core_float(_x, log_mantissa, e);
112
113 // Add the logarithm of the exponent back to the result.
114 Packet x;
115 if (base2) {
116 const Packet cst_log2e = pset1<Packet>(static_cast<float>(EIGEN_LOG2E));
117 x = pmadd(log_mantissa, cst_log2e, e);
118 } else {
119 const Packet cst_ln2 = pset1<Packet>(static_cast<float>(EIGEN_LN2));
120 x = pmadd(e, cst_ln2, log_mantissa);
121 }
122
123 // Filter out invalid inputs:
124 // - negative arg → NAN
125 // - 0 → -INF
126 // - +INF → +INF
127 const Packet cst_minus_inf = por(psignmask<Packet>(), pinf<Packet>());
128 const Packet cst_pos_inf = pinf<Packet>();
129 Packet invalid_mask = pcmp_lt_or_nan(_x, pzero(_x));
130 Packet iszero_mask = pcmp_eq(_x, pzero(_x));
131 Packet pos_inf_mask = pcmp_eq(_x, cst_pos_inf);
132 return pselect(iszero_mask, cst_minus_inf, por(pselect(pos_inf_mask, cst_pos_inf, x), invalid_mask));
133}
134
135template <typename Packet>
136EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog_float(const Packet _x) {
137 return plog_impl_float<Packet, /* base2 */ false>(_x);
138}
139
140template <typename Packet>
141EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog2_float(const Packet _x) {
142 return plog_impl_float<Packet, /* base2 */ true>(_x);
143}
144
145// -----------------------------------------------------------------------
146// Double logarithm: shared polynomial + two range-reduction backends
147// -----------------------------------------------------------------------
148
149// Cephes rational-polynomial approximation of log(1+f) for
150// f in [sqrt(0.5)-1, sqrt(2)-1].
151// Evaluates x - 0.5*x^2 + x^3 * P(x)/Q(x) where P and Q are degree-5.
152// See: http://www.netlib.org/cephes/
153template <typename Packet>
154EIGEN_STRONG_INLINE Packet plog_mantissa_double(const Packet x) {
155 const Packet cst_cephes_log_p0 = pset1<Packet>(1.01875663804580931796E-4);
156 const Packet cst_cephes_log_p1 = pset1<Packet>(4.97494994976747001425E-1);
157 const Packet cst_cephes_log_p2 = pset1<Packet>(4.70579119878881725854E0);
158 const Packet cst_cephes_log_p3 = pset1<Packet>(1.44989225341610930846E1);
159 const Packet cst_cephes_log_p4 = pset1<Packet>(1.79368678507819816313E1);
160 const Packet cst_cephes_log_p5 = pset1<Packet>(7.70838733755885391666E0);
161 // Q0 = 1.0; pmadd(1, x, q1) simplifies to padd(x, q1).
162 const Packet cst_cephes_log_q1 = pset1<Packet>(1.12873587189167450590E1);
163 const Packet cst_cephes_log_q2 = pset1<Packet>(4.52279145837532221105E1);
164 const Packet cst_cephes_log_q3 = pset1<Packet>(8.29875266912776603211E1);
165 const Packet cst_cephes_log_q4 = pset1<Packet>(7.11544750618563894466E1);
166 const Packet cst_cephes_log_q5 = pset1<Packet>(2.31251620126765340583E1);
167
168 Packet x2 = pmul(x, x);
169 Packet x3 = pmul(x2, x);
170
171 // Evaluate P and Q simultaneously for better ILP.
172 Packet y, y1, y_;
173 y = pmadd(cst_cephes_log_p0, x, cst_cephes_log_p1);
174 y1 = pmadd(cst_cephes_log_p3, x, cst_cephes_log_p4);
175 y = pmadd(y, x, cst_cephes_log_p2);
176 y1 = pmadd(y1, x, cst_cephes_log_p5);
177 y_ = pmadd(y, x3, y1);
178
179 y = padd(x, cst_cephes_log_q1);
180 y1 = pmadd(cst_cephes_log_q3, x, cst_cephes_log_q4);
181 y = pmadd(y, x, cst_cephes_log_q2);
182 y1 = pmadd(y1, x, cst_cephes_log_q5);
183 y = pmadd(y, x3, y1);
184
185 y_ = pmul(y_, x3);
186 y = pdiv(y_, y);
187 y = pnmadd(pset1<Packet>(0.5), x2, y);
188 return padd(x, y);
189}
190
191// Detect whether unpacket_traits<Packet>::integer_packet is defined.
192template <typename Packet, typename = void>
193struct packet_has_integer_packet : std::false_type {};
194template <typename Packet>
195struct packet_has_integer_packet<Packet, void_t<typename unpacket_traits<Packet>::integer_packet>> : std::true_type {};
196
197// Dispatch struct for double-precision range reduction.
198// Primary template: pfrexp-based fallback (used when integer_packet is absent).
199template <typename Packet, bool UseIntegerPacket>
200struct plog_range_reduce_double {
201 EIGEN_STRONG_INLINE static void run(const Packet v, Packet& f, Packet& e) {
202 const Packet one = pset1<Packet>(1.0);
203 const Packet cst_cephes_SQRTHF = pset1<Packet>(0.70710678118654752440E0);
204 // pfrexp: f in [0.5, 1), e = unbiased exponent as double.
205 f = pfrexp(v, e);
206 // Shift [0.5,1) -> [sqrt(0.5)-1, sqrt(2)-1] with exponent correction:
207 // if f < sqrt(0.5): f = f + f - 1, e -= 1 (giving f in [0, sqrt(2)-1))
208 // else: f = f - 1 (giving f in [sqrt(0.5)-1, 0))
209 Packet mask = pcmp_lt(f, cst_cephes_SQRTHF);
210 Packet tmp = pand(f, mask);
211 f = psub(f, one);
212 e = psub(e, pand(one, mask));
213 f = padd(f, tmp);
214 }
215};
216
217// Specialisation: fast integer-bit-manipulation path (musl-inspired).
218// Requires unpacket_traits<Packet>::integer_packet to be a 64-bit integer packet.
219template <typename Packet>
220struct plog_range_reduce_double<Packet, true> {
221 EIGEN_STRONG_INLINE static void run(const Packet v, Packet& f, Packet& e) {
222 using PacketI = typename unpacket_traits<Packet>::integer_packet;
223 // 2^-1022: smallest positive normal double.
224 const PacketI cst_min_normal = pset1<PacketI>(static_cast<int64_t>(0x0010000000000000LL));
225 // Lower 52-bit mask (IEEE mantissa field).
226 const PacketI cst_mant_mask = pset1<PacketI>(static_cast<int64_t>(0x000FFFFFFFFFFFFFLL));
227 // Offset = 1.0_bits - sqrt(0.5)_bits. Adding this to the integer
228 // representation shifts the exponent field so that the [sqrt(0.5), sqrt(2))
229 // half-octave boundary falls on an exact biased-exponent boundary, letting
230 // us extract e with a single right shift. The constant is:
231 // 0x3FF0000000000000 - 0x3FE6A09E667F3BCD = 0x00095F619980C433
232 const PacketI cst_sqrt_half_offset =
233 pset1<PacketI>(static_cast<int64_t>(0x3FF0000000000000LL - 0x3FE6A09E667F3BCDLL));
234 // IEEE double exponent bias (1023).
235 const PacketI cst_exp_bias = pset1<PacketI>(static_cast<int64_t>(1023));
236 // sqrt(0.5) IEEE bits — used to reconstruct f from biased mantissa.
237 const PacketI cst_half_mant = pset1<PacketI>(static_cast<int64_t>(0x3FE6A09E667F3BCDLL));
238
239 // Reinterpret v as a 64-bit integer vector.
240 PacketI vi = preinterpret<PacketI>(v);
241
242 // Normalise denormals: multiply by 2^52 and correct the exponent by -52.
243 PacketI is_denormal = pcmp_lt(vi, cst_min_normal);
244 // 2^52 via bit pattern: biased exponent = 52 + 1023 = 0x433, mantissa = 0.
245 Packet v_norm = pmul(v, pset1frombits<Packet>(static_cast<uint64_t>(int64_t(52 + 0x3ff) << 52)));
246 vi = pselect(is_denormal, preinterpret<PacketI>(v_norm), vi);
247 PacketI denorm_adj = pand(is_denormal, pset1<PacketI>(static_cast<int64_t>(52)));
248
249 // Bias the integer representation so the exponent field directly encodes
250 // the half-octave index.
251 PacketI vi_biased = padd(vi, cst_sqrt_half_offset);
252 // Extract unbiased exponent: shift out mantissa bits, subtract IEEE bias
253 // and denormal adjustment.
254 PacketI e_int = psub(psub(plogical_shift_right<52>(vi_biased), cst_exp_bias), denorm_adj);
255 // Convert integer exponent to floating-point.
256 e = pcast<PacketI, Packet>(e_int);
257
258 // Reconstruct mantissa in [sqrt(0.5), sqrt(2)) via integer arithmetic.
259 // The integer addition of the masked mantissa bits and the sqrt(0.5) bit
260 // pattern carries into the exponent field, yielding a value in that range.
261 // Then subtract 1 to centre on 0: f in [sqrt(0.5)-1, sqrt(2)-1].
262 f = psub(preinterpret<Packet>(padd(pand(vi_biased, cst_mant_mask), cst_half_mant)), pset1<Packet>(1.0));
263 }
264};
265
266// Core range reduction and polynomial for double logarithm.
267// Input: v > 0 (zero / negative / inf / nan are handled by the caller).
268// Output: log_mantissa ≈ log(mantissa of v in [sqrt(0.5), sqrt(2))),
269// e = unbiased exponent of v as a double.
270// Selects the fast integer path when integer_packet is available, otherwise
271// falls back to pfrexp.
272template <typename Packet>
273EIGEN_STRONG_INLINE void plog_core_double(const Packet v, Packet& log_mantissa, Packet& e) {
274 Packet f;
275 plog_range_reduce_double<Packet, packet_has_integer_packet<Packet>::value>::run(v, f, e);
276 log_mantissa = plog_mantissa_double(f);
277}
278
279/* Returns the base e (2.718...) or base 2 logarithm of x.
280 * The argument is separated into its exponent and fractional parts.
281 * The logarithm of the fraction in the interval [sqrt(1/2), sqrt(2)],
282 * is approximated by
283 *
284 * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x).
285 *
286 * for more detail see: http://www.netlib.org/cephes/
287 */
288template <typename Packet, bool base2>
289EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog_impl_double(const Packet _x) {
290 const Packet cst_minus_inf = por(psignmask<Packet>(), pinf<Packet>());
291 const Packet cst_pos_inf = pinf<Packet>();
292
293 Packet log_mantissa, e;
294 plog_core_double(_x, log_mantissa, e);
295
296 // Combine: log(x) = e * ln2 + log(mantissa), or log2(x) = log(mantissa)*log2e + e.
297 Packet x;
298 if (base2) {
299 const Packet cst_log2e = pset1<Packet>(static_cast<double>(EIGEN_LOG2E));
300 x = pmadd(log_mantissa, cst_log2e, e);
301 } else {
302 const Packet cst_ln2 = pset1<Packet>(static_cast<double>(EIGEN_LN2));
303 x = pmadd(e, cst_ln2, log_mantissa);
304 }
305
306 Packet invalid_mask = pcmp_lt_or_nan(_x, pzero(_x));
307 Packet iszero_mask = pcmp_eq(_x, pzero(_x));
308 Packet pos_inf_mask = pcmp_eq(_x, cst_pos_inf);
309 // Filter out invalid inputs:
310 // - negative arg → NAN
311 // - 0 → -INF
312 // - +INF → +INF
313 return pselect(iszero_mask, cst_minus_inf, por(pselect(pos_inf_mask, cst_pos_inf, x), invalid_mask));
314}
315
316template <typename Packet>
317EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog_double(const Packet _x) {
318 return plog_impl_double<Packet, /* base2 */ false>(_x);
319}
320
321template <typename Packet>
322EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog2_double(const Packet _x) {
323 return plog_impl_double<Packet, /* base2 */ true>(_x);
324}
325
332template <typename Packet>
333EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_log1p_float(const Packet& x) {
334 const Packet one = pset1<Packet>(1.0f);
335 const Packet cst_minus_inf = por(psignmask<Packet>(), pinf<Packet>());
336 const Packet cst_pos_inf = pinf<Packet>();
337
338 // u = 1 + x, with rounding. Recover the lost low bits: dx = x - (u - 1).
339 Packet u = padd(one, x);
340 Packet dx = psub(x, psub(u, one));
341
342 // For |x| tiny enough that u rounds to 1, return x directly.
343 Packet small_mask = pcmp_eq(u, one);
344 // For u = +inf (x very large), return +inf.
345 Packet inf_mask = pcmp_eq(u, cst_pos_inf);
346
347 // Core range reduction and polynomial on u.
348 Packet log_u, e;
349 plog_core_float(u, log_u, e);
350
351 // result = e * ln2 + log(u) + dx/u.
352 // The dx/u term corrects for the rounding error in u = fl(1+x).
353 const Packet cst_ln2 = pset1<Packet>(static_cast<float>(EIGEN_LN2));
354 Packet result = pmadd(e, cst_ln2, padd(log_u, pdiv(dx, u)));
355
356 // Handle special cases.
357 Packet neg_mask = pcmp_lt(u, pzero(u));
358 Packet zero_mask = pcmp_eq(x, pset1<Packet>(-1.0f));
359 result = pselect(small_mask, x, result);
360 result = pselect(inf_mask, cst_pos_inf, result);
361 result = pselect(zero_mask, cst_minus_inf, result);
362 result = por(neg_mask, result); // NaN for x < -1
363 return result;
364}
365
372template <typename Packet>
373EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_log1p_double(const Packet& x) {
374 const Packet one = pset1<Packet>(1.0);
375 const Packet cst_minus_inf = por(psignmask<Packet>(), pinf<Packet>());
376 const Packet cst_pos_inf = pinf<Packet>();
377
378 // u = 1 + x, with rounding. Recover the lost low bits: dx = x - (u - 1).
379 Packet u = padd(one, x);
380 Packet dx = psub(x, psub(u, one));
381
382 // For |x| tiny enough that u rounds to 1, return x directly.
383 Packet small_mask = pcmp_eq(u, one);
384 // For u = +inf (x very large), return +inf.
385 Packet inf_mask = pcmp_eq(u, cst_pos_inf);
386
387 // Core range reduction and polynomial on u.
388 Packet log_u, e;
389 plog_core_double(u, log_u, e);
390
391 // result = e * ln2 + log(u) + dx/u.
392 // The dx/u term corrects for the rounding error in u = fl(1+x).
393 const Packet cst_ln2 = pset1<Packet>(static_cast<double>(EIGEN_LN2));
394 Packet result = pmadd(e, cst_ln2, padd(log_u, pdiv(dx, u)));
395
396 // Handle special cases.
397 Packet neg_mask = pcmp_lt(u, pzero(u));
398 Packet zero_mask = pcmp_eq(x, pset1<Packet>(-1.0));
399 result = pselect(small_mask, x, result);
400 result = pselect(inf_mask, cst_pos_inf, result);
401 result = pselect(zero_mask, cst_minus_inf, result);
402 result = por(neg_mask, result); // NaN for x < -1
403 return result;
404}
405
410template <typename Packet>
411EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_log1p(const Packet& x) {
412 using ScalarType = typename unpacket_traits<Packet>::type;
413 const Packet one = pset1<Packet>(ScalarType(1));
414 Packet xp1 = padd(x, one);
415 Packet small_mask = pcmp_eq(xp1, one);
416 Packet log1 = plog(xp1);
417 Packet inf_mask = pcmp_eq(xp1, log1);
418 Packet log_large = pmul(x, pdiv(log1, psub(xp1, one)));
419 return pselect(por(small_mask, inf_mask), x, log_large);
420}
421
425template <typename Packet>
426EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_expm1(const Packet& x) {
427 using ScalarType = typename unpacket_traits<Packet>::type;
428 const Packet one = pset1<Packet>(ScalarType(1));
429 const Packet neg_one = pset1<Packet>(ScalarType(-1));
430 Packet u = pexp(x);
431 Packet one_mask = pcmp_eq(u, one);
432 Packet u_minus_one = psub(u, one);
433 Packet neg_one_mask = pcmp_eq(u_minus_one, neg_one);
434 Packet logu = plog(u);
435 // The following comparison is to catch the case where
436 // exp(x) = +inf. It is written in this way to avoid having
437 // to form the constant +inf, which depends on the packet
438 // type.
439 Packet pos_inf_mask = pcmp_eq(logu, u);
440 Packet expm1 = pmul(u_minus_one, pdiv(x, logu));
441 expm1 = pselect(pos_inf_mask, u, expm1);
442 return pselect(one_mask, x, pselect(neg_one_mask, neg_one, expm1));
443}
444
445// exp(r) for r in [-ln(2)/2, ln(2)/2], by a 6th order minimax polynomial.
446template <typename Packet>
447EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet pexp_float_reduced(const Packet& r) {
448 const Packet cst_one = pset1<Packet>(1.0f);
449 const Packet cst_p2 = pset1<Packet>(0.49999988079071044921875f);
450 const Packet cst_p3 = pset1<Packet>(0.16666518151760101318359375f);
451 const Packet cst_p4 = pset1<Packet>(4.166965186595916748046875e-2f);
452 const Packet cst_p5 = pset1<Packet>(8.36894474923610687255859375e-3f);
453 const Packet cst_p6 = pset1<Packet>(1.37449637986719608306884765625e-3f);
454
455 const Packet r2 = pmul(r, r);
456 Packet p_even = pmadd(r2, cst_p6, cst_p4);
457 const Packet p_odd = pmadd(r2, cst_p5, cst_p3);
458 p_even = pmadd(r2, p_even, cst_p2);
459 const Packet p_low = padd(r, cst_one);
460 const Packet y = pmadd(r, p_odd, p_even);
461 return pmadd(r2, y, p_low);
462}
463
464// Exponential function. Works by writing "x = m*log(2) + r" where
465// "m = rint(x/log(2))" and "r" is the remainder. The result is then
466// "exp(x) = 2^m*exp(r)" where exp(r) is in the range [-1,1).
467// exp(r) is computed using a 6th order minimax polynomial approximation.
468template <typename Packet, bool IsFinite>
469EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp_float(const Packet _x) {
470 using PacketI = typename unpacket_traits<Packet>::integer_packet;
471
472 const Packet cst_exp_hi = pset1<Packet>(88.723f);
473 const Packet cst_exp_lo = pset1<Packet>(-104.f);
474
475 const Packet cst_cephes_LOG2EF = pset1<Packet>(1.44269504088896341f);
476
477 // Clamp x to prevent overflow/underflow.
478 Packet x = pmin(pmax(_x, cst_exp_lo), cst_exp_hi);
479
480 // Express exp(x) as exp(m*ln(2) + r), start by extracting
481 // m = rint(x/ln(2)).
482 Packet m = print(pmul(x, cst_cephes_LOG2EF));
483
484 // Get r = x - m*ln(2). m*ln(2) is subtracted out in two parts,
485 // m*C1+m*C2 = m*ln(2), to avoid accumulating truncation errors.
486 const Packet cst_cephes_exp_C1 = pset1<Packet>(-0.693359375f);
487 const Packet cst_cephes_exp_C2 = pset1<Packet>(2.12194440e-4f);
488 Packet r = pmadd(m, cst_cephes_exp_C1, x);
489 r = pmadd(m, cst_cephes_exp_C2, r);
490
491 Packet y = pexp_float_reduced(r);
492
493 // Construct the result y * 2^m via a 2-way exponent split. Writing
494 // 2^m = 2^floor(m/2) * 2^(m - floor(m/2))
495 // keeps each constructed power-of-two within the normal float range (since
496 // |m| <= 150 after the input clamp implies each half lies in [-75, 65]), so
497 // the IEEE-correct rounding of normal*normal handles the subnormal output
498 // range without special-casing.
499 //
500 // To minimize integer ops we fold the bias into the split:
501 // biased_sum = m + 254 (always nonnegative)
502 // biased_hi = biased_sum >> 1 = m/2 + 127
503 // biased_lo = biased_sum - biased_hi = (m - m/2) + 127
504 // so each <<23 directly yields the float bit pattern for 2^(m/2) and
505 // 2^(m - m/2).
506 const PacketI cst_double_bias = pset1<PacketI>(254);
507 const PacketI mi = pcast<Packet, PacketI>(m);
508 const PacketI biased_sum = padd(mi, cst_double_bias);
509 const PacketI biased_hi = plogical_shift_right<1>(biased_sum); // m/2 + 127
510 const PacketI biased_lo = psub(biased_sum, biased_hi); // (m - m/2) + 127
511 const Packet pow2_hi = preinterpret<Packet>(plogical_shift_left<23>(biased_hi));
512 const Packet pow2_lo = preinterpret<Packet>(plogical_shift_left<23>(biased_lo));
513 y = pmul(pmul(y, pow2_hi), pow2_lo);
514
515 EIGEN_IF_CONSTEXPR (!IsFinite) {
516 // Handle NaN: exp(nan) = nan. Use pmax to propagate NaN from input.
517 y = pmax(y, _x);
518 }
519 return y;
520}
521
522// exp(g) for g in [-ln(2)/2, ln(2)/2], by the rational interpolant exp(g) = 1 + 2 g P(g^2) / (Q(g^2) - g P(g^2)).
523template <typename Packet>
524EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet pexp_double_reduced(const Packet& g) {
525 const Packet cst_1 = pset1<Packet>(1.0);
526 const Packet cst_2 = pset1<Packet>(2.0);
527 const Packet cst_cephes_exp_p0 = pset1<Packet>(1.26177193074810590878e-4);
528 const Packet cst_cephes_exp_p1 = pset1<Packet>(3.02994407707441961300e-2);
529 const Packet cst_cephes_exp_p2 = pset1<Packet>(9.99999999999999999910e-1);
530 const Packet cst_cephes_exp_q0 = pset1<Packet>(3.00198505138664455042e-6);
531 const Packet cst_cephes_exp_q1 = pset1<Packet>(2.52448340349684104192e-3);
532 const Packet cst_cephes_exp_q2 = pset1<Packet>(2.27265548208155028766e-1);
533 const Packet cst_cephes_exp_q3 = pset1<Packet>(2.00000000000000000009e0);
534
535 const Packet x2 = pmul(g, g);
536
537 // Evaluate the numerator polynomial of the rational interpolant.
538 Packet px = cst_cephes_exp_p0;
539 px = pmadd(px, x2, cst_cephes_exp_p1);
540 px = pmadd(px, x2, cst_cephes_exp_p2);
541 px = pmul(px, g);
542
543 // Evaluate the denominator polynomial of the rational interpolant.
544 Packet qx = cst_cephes_exp_q0;
545 qx = pmadd(qx, x2, cst_cephes_exp_q1);
546 qx = pmadd(qx, x2, cst_cephes_exp_q2);
547 qx = pmadd(qx, x2, cst_cephes_exp_q3);
548
549 // exp(g) = 1 + 2*px/(qx - px).
550 return pmadd(cst_2, pdiv(px, psub(qx, px)), cst_1);
551}
552
553template <typename Packet>
554EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet pexp_double(const Packet _x) {
555 const Packet cst_exp_hi = pset1<Packet>(709.784);
556 const Packet cst_exp_lo = pset1<Packet>(-745.519);
557 const Packet cst_pldexp_threshold = pset1<Packet>(708.0);
558 const Packet cst_cephes_LOG2EF = pset1<Packet>(1.4426950408889634073599);
559 const Packet cst_cephes_exp_C1 = pset1<Packet>(0.693145751953125);
560 const Packet cst_cephes_exp_C2 = pset1<Packet>(1.42860682030941723212e-6);
561
562 // Clamp x.
563 Packet zero_mask = pcmp_lt(_x, cst_exp_lo);
564 Packet x = pmin(_x, cst_exp_hi);
565
566 // Express exp(x) as exp(g + n*log(2)).
567 // n = rint(x / ln(2)).
568 Packet fx = print(pmul(x, cst_cephes_LOG2EF));
569
570 // Get the remainder modulo log(2), i.e. the "g" described above. Subtract
571 // n*log(2) out in two steps, i.e. n*C1 + n*C2, C1+C2=log2 to get the last
572 // digits right.
573 x = pnmadd(fx, cst_cephes_exp_C1, x);
574 x = pnmadd(fx, cst_cephes_exp_C2, x);
575
576 x = pexp_double_reduced(x);
577
578 // Construct the result 2^n * exp(g) = e * x. The max is used to catch
579 // non-finite values in the input.
580 const Packet fast_pldexp_unsafe = pcmp_lt(cst_pldexp_threshold, pabs(_x));
581 if (!predux_any(fast_pldexp_unsafe)) {
582 // For |x| <= 708, we know the result is not zero or inf, and we can safely use
583 // the fast version of pldexp.
584 return pmax(pldexp_fast(x, fx), _x);
585 }
586 return pandnot(pmax(pldexp(x, fx), _x), zero_mask);
587}
588
589template <typename Packet, typename Scalar = typename unpacket_traits<Packet>::type>
590struct pexp_reduced_impl;
591template <typename Packet>
592struct pexp_reduced_impl<Packet, float> {
593 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run(const Packet& r) { return pexp_float_reduced(r); }
594};
595template <typename Packet>
596struct pexp_reduced_impl<Packet, double> {
597 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run(const Packet& r) { return pexp_double_reduced(r); }
598};
599
600// 2^f for |f| <= 1/2: f ln(2) = r_hi + r_lo with ln(2) = ln2_hi + ln2_lo, and exp(r) = exp(r_hi) (1 + r_lo) +
601// O(r_lo^2).
602template <typename Packet>
603EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_exp2_reduced(const Packet& f) {
604 using Scalar = typename unpacket_traits<Packet>::type;
605 // ln(2) - ln2_hi, from (double(ln(2)) - ln2_hi) exact in double plus ln(2) - double(ln(2)).
606 const Scalar ln2_hi = Scalar(EIGEN_LN2);
607 const Scalar ln2_lo = Scalar((static_cast<double>(EIGEN_LN2) - double(ln2_hi)) + 2.3190468138462996e-17);
608 Packet r_hi, r_lo;
609 twoprod(pset1<Packet>(ln2_hi), f, r_hi, r_lo);
610 r_lo = pmadd(pset1<Packet>(ln2_lo), f, r_lo);
611 const Packet e = pexp_reduced_impl<Packet>::run(r_hi);
612 return pmadd(e, r_lo, e);
613}
614
615// exp2(x) = 2^n 2^f with n = rint(x) and f = x - n, which is exact with |f| <= 1/2. So exp2(n) = 2^n exactly, and
616// neither the reduction nor the scaling adds an error that grows with |x|.
617template <typename Packet>
618EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet generic_exp2(const Packet& _x) {
619 using Scalar = typename unpacket_traits<Packet>::type;
620 constexpr int max_exponent = std::numeric_limits<Scalar>::max_exponent;
621 constexpr int digits = std::numeric_limits<Scalar>::digits;
622 // Beyond these, the result is inf or rounds to 0; within them, n / 2 and n - n / 2 are normal exponents.
623 constexpr Scalar max_cap = Scalar(max_exponent + 1);
624 constexpr Scalar min_cap = -Scalar(max_exponent + digits - 1);
625 const Packet x = pmax(pmin(_x, pset1<Packet>(max_cap)), pset1<Packet>(min_cap));
626 const Packet n = print(x);
627 const Packet y = generic_exp2_reduced(psub(x, n));
628 // One pldexp_fast while 2^n is normal. Near the ends of the range, y 2^n = (y 2^h) 2^(n - h) with h = rint(n / 2):
629 // both powers are normal and the first product is exact, so only the last one rounds, also into the subnormal range.
630 // The barrier keeps -ffast-math from forming 2^h 2^(n - h), which overflows for n = max_exponent.
631 if (!predux_any(pcmp_lt(pset1<Packet>(Scalar(max_exponent - 2)), pabs(n)))) return pldexp_fast(y, n);
632 const Packet h = print(pmul(n, pset1<Packet>(Scalar(0.5))));
633 Packet out = pldexp_fast(y, h);
634 EIGEN_OPTIMIZATION_BARRIER(out)
635 return pldexp_fast(out, psub(n, h));
636}
637
643template <typename Packet>
644EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog10_float(const Packet& x) {
645 // log10(e) in higher precision, split into hi+lo so log_x*(hi+lo) is reconstructed via FMA.
646 // hi = round-to-nearest-float of log10(e); lo = float(log10(e) - hi).
647 const Packet cst_log10e_hi = pset1<Packet>(0.4342944920063018f);
648 const Packet cst_log10e_lo = pset1<Packet>(-1.0103049952192578e-08f);
649 const Packet cst_inf = pinf<Packet>();
650 const Packet cst_zero = pzero(x);
651
652 const Packet log_x = plog(x);
653 const Packet finite_mask = pcmp_lt(pabs(log_x), cst_inf);
654 const Packet finite_log_x = pselect(finite_mask, log_x, cst_zero);
655 const Packet split_log10_x = pmadd(finite_log_x, cst_log10e_hi, pmul(finite_log_x, cst_log10e_lo));
656 return pselect(finite_mask, split_log10_x, log_x);
657}
658
662template <typename Packet>
663EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS Packet plog10_double(const Packet& x) {
664 const Packet cst_log10e = pset1<Packet>(0.43429448190325182);
665 return pmul(plog(x), cst_log10e);
666}
667
668} // end namespace internal
669} // end namespace Eigen
670
671// Include the split-out sections. Order matters: Pow depends on exp/log and FrexpLdexp,
672// Trig depends on exp (for ptanh_float), Complex depends on Trig (for psincos_selector).
673#include "GenericPacketMathPow.h"
674#include "GenericPacketMathTrig.h"
675#include "GenericPacketMathComplex.h"
676
677namespace Eigen {
678namespace internal {
679
680//----------------------------------------------------------------------
681// Sign Function
682//----------------------------------------------------------------------
683
684template <typename Packet, typename Scalar = typename unpacket_traits<Packet>::type>
685struct psign_uses_binary_encoding
686 : bool_constant<!is_scalar<Packet>::value && packet_has_integer_packet<Packet>::value &&
687 (std::is_same<Scalar, float>::value || std::is_same<Scalar, double>::value)> {};
688
689template <typename Packet>
690struct psign_impl<Packet, std::enable_if_t<psign_uses_binary_encoding<Packet>::value>> {
691 static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a) {
692 using Scalar = typename unpacket_traits<Packet>::type;
693 using PacketI = typename unpacket_traits<Packet>::integer_packet;
694 using IntScalar = typename unpacket_traits<PacketI>::type;
695 using Binary = binary_floating_point_traits<Scalar>;
696
697 // Magnitude is a nonnegative integer. Comparing it with 1 avoids Clang
698 // folding an integer == 0 test into a DAZ-sensitive FP comparison.
699 const PacketI magnitude = pand(preinterpret<PacketI>(a), pset1<PacketI>(IntScalar(~Binary::kSignBit)));
700 const Packet is_zero = preinterpret<Packet>(pcmp_lt(magnitude, pset1<PacketI>(IntScalar(1))));
701 const Packet is_nan = preinterpret<Packet>(pcmp_lt(pset1<PacketI>(IntScalar(Binary::kExponentMask)), magnitude));
702 const Packet signed_one = por(pandnot(a, pabs(a)), pset1<Packet>(Scalar(1)));
703 return pselect(is_nan, a, pandnot(signed_one, is_zero));
704 }
705};
706
707template <typename Packet>
708struct psign_impl<Packet, std::enable_if_t<!psign_uses_binary_encoding<Packet>::value && !is_scalar<Packet>::value &&
709 !NumTraits<typename unpacket_traits<Packet>::type>::IsComplex &&
710 !NumTraits<typename unpacket_traits<Packet>::type>::IsInteger>> {
711 static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a) {
712 using Scalar = typename unpacket_traits<Packet>::type;
713 const Packet cst_one = pset1<Packet>(Scalar(1));
714
715 const Packet abs_a = pabs(a);
716 const Packet sign_mask = pandnot(a, abs_a);
717 const Packet zero_mask = pcmp_eq(abs_a, pzero(abs_a));
718
719 return pselect(pisnan(a), a, pselect(zero_mask, abs_a, por(sign_mask, cst_one)));
720 }
721};
722
723template <typename Packet>
724struct psign_impl<Packet, std::enable_if_t<!is_scalar<Packet>::value &&
725 !NumTraits<typename unpacket_traits<Packet>::type>::IsComplex &&
726 NumTraits<typename unpacket_traits<Packet>::type>::IsSigned &&
727 NumTraits<typename unpacket_traits<Packet>::type>::IsInteger>> {
728 static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a) {
729 using Scalar = typename unpacket_traits<Packet>::type;
730 const Packet cst_one = pset1<Packet>(Scalar(1));
731 const Packet cst_minus_one = pset1<Packet>(Scalar(-1));
732 const Packet cst_zero = pzero(a);
733
734 const Packet positive_mask = pcmp_lt(cst_zero, a);
735 const Packet positive = pand(positive_mask, cst_one);
736 const Packet negative_mask = pcmp_lt(a, cst_zero);
737 const Packet negative = pand(negative_mask, cst_minus_one);
738
739 return por(positive, negative);
740 }
741};
742
743template <typename Packet>
744struct psign_impl<Packet, std::enable_if_t<!is_scalar<Packet>::value &&
745 !NumTraits<typename unpacket_traits<Packet>::type>::IsComplex &&
746 !NumTraits<typename unpacket_traits<Packet>::type>::IsSigned &&
747 NumTraits<typename unpacket_traits<Packet>::type>::IsInteger>> {
748 static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a) {
749 using Scalar = typename unpacket_traits<Packet>::type;
750 const Packet cst_one = pset1<Packet>(Scalar(1));
751 const Packet cst_zero = pzero(a);
752
753 const Packet zero_mask = pcmp_eq(cst_zero, a);
754 return pandnot(cst_one, zero_mask);
755 }
756};
757
758// \internal \returns the sign of a complex number z, defined as z / abs(z).
759template <typename Packet>
760struct psign_impl<Packet, std::enable_if_t<!is_scalar<Packet>::value &&
761 NumTraits<typename unpacket_traits<Packet>::type>::IsComplex &&
762 unpacket_traits<Packet>::vectorizable>> {
763 static EIGEN_DEVICE_FUNC inline Packet run(const Packet& a) {
764 using Scalar = typename unpacket_traits<Packet>::type;
765 using RealScalar = typename Scalar::value_type;
766 using RealPacket = typename unpacket_traits<Packet>::as_real;
767
768 // Step 1. Compute (for each element z = x + i*y in a)
769 // l = abs(z) = sqrt(x^2 + y^2).
770 // To avoid over- and underflow, we use the stable formula for each hypotenuse
771 // l = (zmin == 0 ? zmax : zmax * sqrt(1 + (zmin/zmax)**2)),
772 // where zmax = max(|x|, |y|), zmin = min(|x|, |y|),
773 RealPacket a_abs = pabs(a.v);
774 RealPacket a_abs_flip = pcplxflip(Packet(a_abs)).v;
775 RealPacket a_max = pmax(a_abs, a_abs_flip);
776 RealPacket a_min = pmin(a_abs, a_abs_flip);
777 RealPacket a_min_zero_mask = pcmp_eq(a_min, pzero(a_min));
778 RealPacket a_max_zero_mask = pcmp_eq(a_max, pzero(a_max));
779 RealPacket r = pdiv(a_min, a_max);
780 const RealPacket cst_one = pset1<RealPacket>(RealScalar(1));
781 RealPacket l = pmul(a_max, psqrt(padd(cst_one, pmul(r, r)))); // [l0, l0, l1, l1]
782 // Set l to a_max if a_min is zero, since the roundtrip sqrt(a_max^2) may be
783 // lossy.
784 l = pselect(a_min_zero_mask, a_max, l);
785 // Step 2 compute a / abs(a).
786 RealPacket sign_as_real = pandnot(pdiv(a.v, l), a_max_zero_mask);
787 Packet sign;
788 sign.v = sign_as_real;
789 return sign;
790 }
791};
792
793//----------------------------------------------------------------------
794// Rounding Functions
795//----------------------------------------------------------------------
796
797template <typename Packet>
798EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_rint(const Packet& a) {
799 using Scalar = typename unpacket_traits<Packet>::type;
800 using IntType = typename numext::get_integer_by_size<sizeof(Scalar)>::signed_type;
801 // Adds and subtracts signum(a) * 2^kMantissaBits to force rounding.
802 const IntType kLimit = IntType(1) << (NumTraits<Scalar>::digits() - 1);
803 const Packet cst_limit = pset1<Packet>(static_cast<Scalar>(kLimit));
804 Packet abs_a = pabs(a);
805 Packet sign_a = pandnot(a, abs_a);
806 Packet rint_a = padd(abs_a, cst_limit);
807 // Don't compile-away addition and subtraction.
808 EIGEN_OPTIMIZATION_BARRIER(rint_a);
809 rint_a = psub(rint_a, cst_limit);
810 rint_a = por(rint_a, sign_a);
811 // If greater than limit (or NaN), simply return a.
812 Packet mask = pcmp_lt(abs_a, cst_limit);
813 Packet result = pselect(mask, rint_a, a);
814 return result;
815}
816
817template <typename Packet>
818EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_floor(const Packet& a) {
819 using Scalar = typename unpacket_traits<Packet>::type;
820 const Packet cst_1 = pset1<Packet>(Scalar(1));
821 Packet rint_a = generic_rint(a);
822 // if a < rint(a), then rint(a) == ceil(a)
823 Packet mask = pcmp_lt(a, rint_a);
824 Packet offset = pand(cst_1, mask);
825 Packet result = psub(rint_a, offset);
826 return result;
827}
828
829template <typename Packet>
830EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_ceil(const Packet& a) {
831 using Scalar = typename unpacket_traits<Packet>::type;
832 const Packet cst_1 = pset1<Packet>(Scalar(1));
833 const Packet sign_mask = psignmask<Packet>();
834 Packet rint_a = generic_rint(a);
835 // if rint(a) < a, then rint(a) == floor(a)
836 Packet mask = pcmp_lt(rint_a, a);
837 Packet offset = pand(cst_1, mask);
838 Packet result = padd(rint_a, offset);
839 // Signed zero must remain signed (e.g. ceil(-0.02) == -0).
840 result = por(result, pand(sign_mask, a));
841 return result;
842}
843
844template <typename Packet>
845EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_trunc(const Packet& a) {
846 Packet abs_a = pabs(a);
847 Packet sign_a = pandnot(a, abs_a);
848 Packet floor_abs_a = generic_floor(abs_a);
849 Packet result = por(floor_abs_a, sign_a);
850 return result;
851}
852
853template <typename Packet>
854EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet generic_round(const Packet& a) {
855 using Scalar = typename unpacket_traits<Packet>::type;
856 const Packet cst_half = pset1<Packet>(Scalar(0.5));
857 const Packet cst_1 = pset1<Packet>(Scalar(1));
858 Packet abs_a = pabs(a);
859 Packet sign_a = pandnot(a, abs_a);
860 Packet floor_abs_a = generic_floor(abs_a);
861 Packet diff = psub(abs_a, floor_abs_a);
862 Packet mask = pcmp_le(cst_half, diff);
863 Packet offset = pand(cst_1, mask);
864 Packet result = padd(floor_abs_a, offset);
865 result = por(result, sign_a);
866 return result;
867}
868
869template <typename Packet>
870struct nearest_integer_packetop_impl<Packet, /*IsScalar*/ false, /*IsInteger*/ false> {
871 using Scalar = typename unpacket_traits<Packet>::type;
872 static_assert(packet_traits<Scalar>::HasRound, "Generic nearest integer functions are disabled for this type.");
873 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_floor(const Packet& x) { return generic_floor(x); }
874 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_ceil(const Packet& x) { return generic_ceil(x); }
875 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_rint(const Packet& x) { return generic_rint(x); }
876 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_round(const Packet& x) { return generic_round(x); }
877 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_trunc(const Packet& x) { return generic_trunc(x); }
878};
879
880template <typename Packet>
881struct nearest_integer_packetop_impl<Packet, /*IsScalar*/ false, /*IsInteger*/ true> {
882 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_floor(const Packet& x) { return x; }
883 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_ceil(const Packet& x) { return x; }
884 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_rint(const Packet& x) { return x; }
885 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_round(const Packet& x) { return x; }
886 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet run_trunc(const Packet& x) { return x; }
887};
888
889} // end namespace internal
890} // end namespace Eigen
891
892#endif // EIGEN_ARCH_GENERIC_PACKET_MATH_FUNCTIONS_H