Fixed-point 2^x. Uses 4-term minimax polynomial for 2^t, t in [0,1). Horner evaluation uses intermediate precision (IFRAC) to minimize rounding error, then converts back to FRAC_BITS.
| 406 | // Horner evaluation uses intermediate precision (IFRAC) to minimize |
| 407 | // rounding error, then converts back to FRAC_BITS. |
| 408 | static FASTLED_FORCE_INLINE Derived exp2_fp(Derived x) { |
| 409 | constexpr int IFRAC = traits::IFRAC; |
| 410 | |
| 411 | Derived fl_val = floor(x); |
| 412 | Derived fr = x - fl_val; |
| 413 | raw_type n = fl_val.mValue >> FRAC_BITS; |
| 414 | if (n >= INT_BITS - 1) return Derived::from_raw(traits::MAX_OVERFLOW); |
| 415 | if (n < -FRAC_BITS) return Derived(); |
| 416 | |
| 417 | raw_type int_pow; |
| 418 | if (n >= 0) { |
| 419 | int_pow = static_cast<raw_type>(static_cast<unsigned_raw_type>(1) << FRAC_BITS) << n; |
| 420 | } else { |
| 421 | int_pow = static_cast<raw_type>(static_cast<unsigned_raw_type>(1) << FRAC_BITS) >> (-n); |
| 422 | } |
| 423 | |
| 424 | // 4-term minimax coefficients for 2^t - 1, t in [0,1). |
| 425 | // Coefficients scaled by 2^IFRAC. |
| 426 | using poly_type = poly_intermediate_type; |
| 427 | constexpr poly_type d0 = static_cast<poly_type>(0.69316 * (1LL << IFRAC)); |
| 428 | constexpr poly_type d1 = static_cast<poly_type>(0.24071 * (1LL << IFRAC)); |
| 429 | constexpr poly_type d2 = static_cast<poly_type>(0.05336 * (1LL << IFRAC)); |
| 430 | constexpr poly_type d3 = static_cast<poly_type>(0.01276 * (1LL << IFRAC)); |
| 431 | |
| 432 | // Extend fr to IFRAC fractional bits |
| 433 | poly_type fr_ifrac = static_cast<poly_type>(fr.mValue) << (IFRAC - FRAC_BITS); |
| 434 | |
| 435 | // Horner: 1 + fr * (d0 + fr * (d1 + fr * (d2 + fr * d3))) |
| 436 | return exp2_horner(int_pow, fr_ifrac, d0, d1, d2, d3, fl::bool_constant<(IFRAC <= 16)>()); |
| 437 | } |
| 438 | |
| 439 | // exp2 Horner evaluation for i32 intermediates (IFRAC <= 16) |
| 440 | template<typename PolyType> |