FastLED 3.9.15
Loading...
Searching...
No Matches
u8x24.h
Go to the documentation of this file.
1#pragma once
2
3// Unsigned 8.24 fixed-point arithmetic.
4// All operations are integer-only in the hot path.
5// Range: [0, 256) with 24 fractional bits.
6
7#include "fl/stl/int.h"
11#include "fl/stl/undef.h" // Undefine abs/min/max macros from Arduino.h
12#include "fl/stl/noexcept.h"
13
15
16namespace fl {
17
18// Unsigned 8.24 fixed-point value type.
19class u8x24 {
20 public:
21 static constexpr int INT_BITS = 8;
22 static constexpr int FRAC_BITS = 24;
23 static constexpr i32 SCALE = static_cast<i32>(1) << FRAC_BITS;
24
25 // ---- Construction ------------------------------------------------------
26
27 constexpr u8x24() FL_NOEXCEPT = default;
28
29 explicit constexpr u8x24(float f) FL_NOEXCEPT
30 : mValue(static_cast<u32>(f * (SCALE))) {}
31
32 // Integer constructor — any integer width (portable: AVR 16-bit int, ARM/x86 32-bit).
33 // Compile error if constexpr value exceeds INT_BITS range.
34 template <typename IntT, detail::enable_if_integer_t<IntT> = 0>
37
38 // Auto-promotion from other fixed-point types
39 template <typename OtherFP>
40 constexpr u8x24(const OtherFP& other,
41 typename fl::enable_if<
42 (OtherFP::INT_BITS <= INT_BITS) &&
43 (OtherFP::FRAC_BITS <= FRAC_BITS) &&
44 (OtherFP::INT_BITS != INT_BITS || OtherFP::FRAC_BITS != FRAC_BITS),
45 int>::type = 0)
46 FL_NOEXCEPT : mValue(static_cast<u32>(
47 static_cast<u64>(other.raw()) << (FRAC_BITS - OtherFP::FRAC_BITS))) {}
48
49 // Raw constructor for C++11 constexpr from_raw
50 struct RawTag {};
51 constexpr explicit u8x24(u32 raw, RawTag) FL_NOEXCEPT : mValue(raw) {}
52
54 return u8x24(raw, RawTag());
55 }
56
57 // ---- Access ------------------------------------------------------------
58
59 constexpr u32 raw() const FL_NOEXCEPT { return mValue; }
60 constexpr u32 to_int() const FL_NOEXCEPT { return mValue >> FRAC_BITS; }
61 constexpr float to_float() const FL_NOEXCEPT { return static_cast<float>(mValue) / (SCALE); }
62
63 // ---- Fixed-point arithmetic --------------------------------------------
64
66 return from_raw(static_cast<u32>(
67 (static_cast<u64>(mValue) * b.mValue) >> FRAC_BITS));
68 }
69
71 return from_raw(static_cast<u32>(
72 (static_cast<u64>(mValue) * (static_cast<u64>(1) << FRAC_BITS)) / b.mValue));
73 }
74
76 return from_raw(mValue + b.mValue);
77 }
78
80 return from_raw(mValue - b.mValue);
81 }
82
83 constexpr FASTLED_FORCE_INLINE u8x24 operator>>(int shift) const FL_NOEXCEPT {
84 return from_raw(mValue >> shift);
85 }
86
87 constexpr FASTLED_FORCE_INLINE u8x24 operator<<(int shift) const FL_NOEXCEPT {
88 return from_raw(mValue << shift);
89 }
90
91 // ---- Scalar multiply (no fixed-point shift) ----------------------------
92
93 constexpr FASTLED_FORCE_INLINE u8x24 operator*(u32 scalar) const FL_NOEXCEPT {
94 return from_raw(mValue * scalar);
95 }
96
97 friend constexpr u8x24 operator*(u32 scalar, u8x24 fp) FL_NOEXCEPT {
98 return u8x24::from_raw(scalar * fp.mValue);
99 }
100
101 // ---- Comparisons -------------------------------------------------------
102
103 constexpr bool operator<(u8x24 b) const FL_NOEXCEPT { return mValue < b.mValue; }
104 constexpr bool operator>(u8x24 b) const FL_NOEXCEPT { return mValue > b.mValue; }
105 constexpr bool operator<=(u8x24 b) const FL_NOEXCEPT { return mValue <= b.mValue; }
106 constexpr bool operator>=(u8x24 b) const FL_NOEXCEPT { return mValue >= b.mValue; }
107 constexpr bool operator==(u8x24 b) const FL_NOEXCEPT { return mValue == b.mValue; }
108 constexpr bool operator!=(u8x24 b) const FL_NOEXCEPT { return mValue != b.mValue; }
109
110 // ---- Math ---------------------------------------------------------------
111
113 return from_raw(a.mValue % b.mValue);
114 }
115
117 return from_raw(x.mValue & ~(u32((SCALE) - 1)));
118 }
119
121 return from_raw((x.mValue & ~(u32((SCALE) - 1))) +
122 ((x.mValue & u32((SCALE) - 1)) ? (SCALE) : 0));
123 }
124
126 return from_raw(x.mValue & u32((SCALE) - 1));
127 }
128
130 return a.mValue < b.mValue ? a : b;
131 }
132
134 return a.mValue > b.mValue ? a : b;
135 }
136
138 return a + (b - a) * t;
139 }
140
142 return x < lo ? lo : (x > hi ? hi : x);
143 }
144
146 return x < edge ? u8x24() : u8x24(1.0f);
147 }
148
150 constexpr u8x24 zero(0.0f);
151 constexpr u8x24 one(1.0f);
152 constexpr u8x24 two(2.0f);
153 constexpr u8x24 three(3.0f);
154 u8x24 t = clamp((x - edge0) / (edge1 - edge0), zero, one);
155 return t * t * (three - two * t);
156 }
157
159 return x.mValue == 0 ? u8x24() : from_raw(static_cast<u32>(
160 fl::isqrt64(static_cast<u64>(x.mValue) << FRAC_BITS)));
161 }
162
164 return sqrt(x).mValue == 0
165 ? u8x24()
166 : from_raw(static_cast<u32>(1) << FRAC_BITS) / sqrt(x);
167 }
168
170 if (base.mValue == 0) return u8x24();
171 constexpr u8x24 one(1.0f);
172 if (exp.mValue == 0) return one;
173 if (base == one) return one;
174 // Snap base values within ~2 ULPs of 1.0 to exactly 1.0 to dodge the
175 // log2(1+t) minimax polynomial's upper-endpoint residual (#2969).
176 constexpr u32 kOneRaw = static_cast<u32>(SCALE);
177 if (base.mValue >= (kOneRaw - 2u) && base.mValue <= kOneRaw) {
178 return one;
179 }
180 return exp2_fp(exp * log2_fp(base));
181 }
182
183 private:
184 u32 mValue = 0;
185
186 // Returns 0-based position of highest set bit, or -1 if v==0.
187 static constexpr FASTLED_FORCE_INLINE int highest_bit(u32 v) FL_NOEXCEPT {
188 return v == 0 ? -1 : _highest_bit_step(v, 0);
189 }
190
191 static constexpr int _highest_bit_step(u32 v, int r) FL_NOEXCEPT {
192 return (v & 0xFFFF0000u) ? _highest_bit_step(v >> 16, r + 16)
193 : (v & 0x0000FF00u) ? _highest_bit_step(v >> 8, r + 8)
194 : (v & 0x000000F0u) ? _highest_bit_step(v >> 4, r + 4)
195 : (v & 0x0000000Cu) ? _highest_bit_step(v >> 2, r + 2)
196 : (v & 0x00000002u) ? r + 1
197 : r;
198 }
199
200 // Fixed-point log base 2 for positive values.
201 // Uses 4-term minimax polynomial for log2(1+t), t in [0,1).
203 u32 val = x.mValue;
204 int msb = highest_bit(val);
205 if (msb < 0) return u8x24(); // log2(0) = -inf, return 0
206
207 u32 int_part = msb - FRAC_BITS;
208 u32 t;
209 if (msb >= FRAC_BITS) {
210 t = (val >> (msb - FRAC_BITS)) - (SCALE);
211 } else {
212 t = (val << (FRAC_BITS - msb)) - (SCALE);
213 }
214
215 // 4-term minimax coefficients for log2(1+t), t in [0,1).
216 constexpr int IFRAC = 24;
217 constexpr u64 c0 = 24189248ULL; // 1.44179 * 2^24
218 constexpr i64 c1 = -11728384LL; // -0.69907 * 2^24
219 constexpr i64 c2 = 6098176LL; // 0.36348 * 2^24
220 constexpr i64 c3 = -1788416LL; // -0.10660 * 2^24
221
222 i64 t24 = static_cast<i64>(t);
223 // Horner: t * (c0 + t * (c1 + t * (c2 + t * c3)))
224 i64 acc = c3;
225 acc = c2 + ((acc * t24) >> IFRAC);
226 acc = c1 + ((acc * t24) >> IFRAC);
227 acc = static_cast<i64>(c0) + ((acc * t24) >> IFRAC);
228 i64 frac_part = (acc * t24) >> IFRAC;
229
230 // Combine integer and fractional parts
231 i64 result = (static_cast<i64>(int_part) << FRAC_BITS) + frac_part;
232 return from_raw(result >= 0 ? static_cast<u32>(result) : 0);
233 }
234
235 // Fixed-point 2^x. Uses 4-term minimax polynomial for 2^t, t in [0,1).
237 u8x24 fl_val = floor(x);
238 u8x24 fr = x - fl_val;
239 u32 n = fl_val.mValue >> FRAC_BITS;
240
241 // Prevent overflow
242 if (n >= INT_BITS) return from_raw(0xFFFFFFFFu);
243
244 u32 int_pow = static_cast<u32>(SCALE) << n;
245
246 // 4-term minimax coefficients for 2^t - 1, t in [0,1).
247 constexpr int IFRAC = 24;
248 constexpr u64 d0 = 11629376ULL; // 0.69316 * 2^24
249 constexpr u64 d1 = 4038400ULL; // 0.24071 * 2^24
250 constexpr u64 d2 = 895232ULL; // 0.05336 * 2^24
251 constexpr u64 d3 = 214016ULL; // 0.01276 * 2^24
252
253 u64 fr24 = static_cast<u64>(fr.mValue);
254 // Horner: 1 + fr * (d0 + fr * (d1 + fr * (d2 + fr * d3)))
255 u64 acc = d3;
256 acc = d2 + ((acc * fr24) >> IFRAC);
257 acc = d1 + ((acc * fr24) >> IFRAC);
258 acc = d0 + ((acc * fr24) >> IFRAC);
259 constexpr u64 one24 = 1ULL << IFRAC;
260 u64 frac_pow24 = one24 + ((acc * fr24) >> IFRAC);
261
262 // Scale by int_pow (result stays at 24 frac bits).
263 u64 result = (static_cast<u64>(int_pow) * frac_pow24) >> FRAC_BITS;
264 return from_raw(static_cast<u32>(result));
265 }
266};
267
268} // namespace fl
269
constexpr bool operator<(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:103
constexpr bool operator==(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:107
constexpr bool operator!=(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:108
static constexpr FASTLED_FORCE_INLINE u8x24 from_raw(u32 raw) FL_NOEXCEPT
Definition u8x24.h:53
constexpr u8x24(const OtherFP &other, typename fl::enable_if<(OtherFP::INT_BITS<=INT_BITS) &&(OtherFP::FRAC_BITS<=FRAC_BITS) &&(OtherFP::INT_BITS !=INT_BITS||OtherFP::FRAC_BITS !=FRAC_BITS), int >::type=0) FL_NOEXCEPT
Definition u8x24.h:40
constexpr FASTLED_FORCE_INLINE u8x24 operator+(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:75
static constexpr int _highest_bit_step(u32 v, int r) FL_NOEXCEPT
Definition u8x24.h:191
constexpr FASTLED_FORCE_INLINE u8x24 operator/(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:70
static constexpr int FRAC_BITS
Definition u8x24.h:22
constexpr u32 to_int() const FL_NOEXCEPT
Definition u8x24.h:60
static constexpr FASTLED_FORCE_INLINE u8x24 step(u8x24 edge, u8x24 x) FL_NOEXCEPT
Definition u8x24.h:145
constexpr FASTLED_FORCE_INLINE u8x24 operator<<(int shift) const FL_NOEXCEPT
Definition u8x24.h:87
constexpr float to_float() const FL_NOEXCEPT
Definition u8x24.h:61
static constexpr int INT_BITS
Definition u8x24.h:21
constexpr FASTLED_FORCE_INLINE u8x24 operator*(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:65
constexpr u8x24() FL_NOEXCEPT=default
constexpr u8x24(u32 raw, RawTag) FL_NOEXCEPT
Definition u8x24.h:51
static FASTLED_FORCE_INLINE u8x24 exp2_fp(u8x24 x) FL_NOEXCEPT
Definition u8x24.h:236
static FASTLED_FORCE_INLINE u8x24 smoothstep(u8x24 edge0, u8x24 edge1, u8x24 x) FL_NOEXCEPT
Definition u8x24.h:149
static constexpr FASTLED_FORCE_INLINE u8x24 fract(u8x24 x) FL_NOEXCEPT
Definition u8x24.h:125
constexpr FASTLED_FORCE_INLINE u8x24 operator*(u32 scalar) const FL_NOEXCEPT
Definition u8x24.h:93
static FASTLED_FORCE_INLINE u8x24 pow(u8x24 base, u8x24 exp) FL_NOEXCEPT
Definition u8x24.h:169
static constexpr FASTLED_FORCE_INLINE u8x24 lerp(u8x24 a, u8x24 b, u8x24 t) FL_NOEXCEPT
Definition u8x24.h:137
static constexpr FASTLED_FORCE_INLINE u8x24 sqrt(u8x24 x) FL_NOEXCEPT
Definition u8x24.h:158
constexpr FASTLED_FORCE_INLINE u8x24 operator>>(int shift) const FL_NOEXCEPT
Definition u8x24.h:83
static constexpr FASTLED_FORCE_INLINE u8x24 ceil(u8x24 x) FL_NOEXCEPT
Definition u8x24.h:120
constexpr u8x24(IntT n) FL_NOEXCEPT
Definition u8x24.h:35
static constexpr FASTLED_FORCE_INLINE u8x24 mod(u8x24 a, u8x24 b) FL_NOEXCEPT
Definition u8x24.h:112
static constexpr FASTLED_FORCE_INLINE u8x24 min(u8x24 a, u8x24 b) FL_NOEXCEPT
Definition u8x24.h:129
static constexpr FASTLED_FORCE_INLINE u8x24 rsqrt(u8x24 x) FL_NOEXCEPT
Definition u8x24.h:163
static constexpr FASTLED_FORCE_INLINE int highest_bit(u32 v) FL_NOEXCEPT
Definition u8x24.h:187
static FASTLED_FORCE_INLINE u8x24 log2_fp(u8x24 x) FL_NOEXCEPT
Definition u8x24.h:202
static constexpr i32 SCALE
Definition u8x24.h:23
friend constexpr u8x24 operator*(u32 scalar, u8x24 fp) FL_NOEXCEPT
Definition u8x24.h:97
constexpr bool operator<=(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:105
static constexpr FASTLED_FORCE_INLINE u8x24 max(u8x24 a, u8x24 b) FL_NOEXCEPT
Definition u8x24.h:133
static constexpr FASTLED_FORCE_INLINE u8x24 clamp(u8x24 x, u8x24 lo, u8x24 hi) FL_NOEXCEPT
Definition u8x24.h:141
constexpr bool operator>(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:104
constexpr FASTLED_FORCE_INLINE u8x24 operator-(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:79
constexpr bool operator>=(u8x24 b) const FL_NOEXCEPT
Definition u8x24.h:106
constexpr u32 raw() const FL_NOEXCEPT
Definition u8x24.h:59
u32 mValue
Definition u8x24.h:184
static constexpr FASTLED_FORCE_INLINE u8x24 floor(u8x24 x) FL_NOEXCEPT
Definition u8x24.h:116
#define constexpr
Declares that it is possible to evaluate a value at compile time, introduced in C++11.
Definition cpp_compat.h:15
fl::i64 i64
Definition s16x16x4.h:222
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
fl::u64 u64
Definition s16x16x4.h:221
enable_if< is_fixed_point< T >::value, T >::type exp(T x) FL_NOEXCEPT
FL_OPTIMIZE_FUNCTION constexpr u32 isqrt64(u64 x) FL_NOEXCEPT
Definition isqrt.h:58
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_OPTIMIZATION_LEVEL_O3_BEGIN
#define FASTLED_FORCE_INLINE
#define FL_OPTIMIZATION_LEVEL_O3_END
#define FL_NOEXCEPT