FastLED 3.9.15
Loading...
Searching...
No Matches
s24x8.h
Go to the documentation of this file.
1#pragma once
2
3// Signed 24.8 fixed-point arithmetic and trigonometry.
4// All operations are integer-only in the hot path.
5
6#include "fl/stl/int.h"
7#include "fl/math/sin32.h"
11#include "fl/stl/noexcept.h"
12#include "fl/stl/undef.h" // Undefine abs/min/max macros from Arduino.h
13
15
16namespace fl {
17
18// Signed 24.8 fixed-point value type.
19class s24x8 {
20 public:
21 static constexpr int INT_BITS = 24;
22 static constexpr int FRAC_BITS = 8;
23 static constexpr i32 SCALE = static_cast<i32>(1) << FRAC_BITS;
24
25 // ---- Construction ------------------------------------------------------
26
27 constexpr s24x8() FL_NOEXCEPT = default;
28
29 explicit constexpr s24x8(float f) FL_NOEXCEPT
30 : mValue(static_cast<i32>(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 s24x8(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<i32>(
47 static_cast<i64>(other.raw()) << (FRAC_BITS - OtherFP::FRAC_BITS))) {}
48
49 // Raw constructor for C++11 constexpr from_raw
50 struct RawTag {};
51 constexpr explicit s24x8(i32 raw, RawTag) FL_NOEXCEPT : mValue(raw) {}
52
54 return s24x8(raw, RawTag());
55 }
56
57 // ---- Access ------------------------------------------------------------
58
59 constexpr i32 raw() const FL_NOEXCEPT { return mValue; }
60 constexpr i32 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<i32>(
67 (static_cast<i64>(mValue) * b.mValue) >> FRAC_BITS));
68 }
69
71 return from_raw(static_cast<i32>(
72 (static_cast<i64>(mValue) * (static_cast<i64>(SCALE))) / b.mValue));
73 }
74
76 return from_raw(static_cast<i32>(
77 static_cast<u32>(mValue) + static_cast<u32>(b.mValue)));
78 }
79
81 return from_raw(static_cast<i32>(
82 static_cast<u32>(mValue) - static_cast<u32>(b.mValue)));
83 }
84
86 return from_raw(static_cast<i32>(0u - static_cast<u32>(mValue)));
87 }
88
89 constexpr FASTLED_FORCE_INLINE s24x8 operator>>(int shift) const FL_NOEXCEPT {
90 return from_raw(mValue >> shift);
91 }
92
93 // ---- Scalar multiply (no fixed-point shift) ----------------------------
94
95 constexpr FASTLED_FORCE_INLINE s24x8 operator*(i32 scalar) const FL_NOEXCEPT {
96 return from_raw(mValue * scalar);
97 }
98
99 friend constexpr s24x8 operator*(i32 scalar, s24x8 fp) FL_NOEXCEPT {
100 return s24x8::from_raw(scalar * fp.mValue);
101 }
102
103 // ---- Comparisons -------------------------------------------------------
104
105 constexpr bool operator<(s24x8 b) const FL_NOEXCEPT { return mValue < b.mValue; }
106 constexpr bool operator>(s24x8 b) const FL_NOEXCEPT { return mValue > b.mValue; }
107 constexpr bool operator<=(s24x8 b) const FL_NOEXCEPT { return mValue <= b.mValue; }
108 constexpr bool operator>=(s24x8 b) const FL_NOEXCEPT { return mValue >= b.mValue; }
109 constexpr bool operator==(s24x8 b) const FL_NOEXCEPT { return mValue == b.mValue; }
110 constexpr bool operator!=(s24x8 b) const FL_NOEXCEPT { return mValue != b.mValue; }
111
112 // ---- Math ---------------------------------------------------------------
113
115 return from_raw(a.mValue % b.mValue);
116 }
117
119 return from_raw(x.mValue & ~(i32((SCALE) - 1)));
120 }
121
123 return from_raw((x.mValue & ~(i32((SCALE) - 1))) +
124 ((x.mValue & i32((SCALE) - 1)) ? (SCALE) : 0));
125 }
126
128 return from_raw(x.mValue & i32((SCALE) - 1));
129 }
130
132 return from_raw(x.mValue < 0 ? -x.mValue : x.mValue);
133 }
134
136 return x.mValue > 0 ? 1 : (x.mValue < 0 ? -1 : 0);
137 }
138
140 return a + (b - a) * t;
141 }
142
144 return x < lo ? lo : (x > hi ? hi : x);
145 }
146
148 return x < edge ? s24x8() : s24x8(1.0f);
149 }
150
152 constexpr s24x8 zero(0.0f);
153 constexpr s24x8 one(1.0f);
154 constexpr s24x8 two(2.0f);
155 constexpr s24x8 three(3.0f);
156 s24x8 t = clamp((x - edge0) / (edge1 - edge0), zero, one);
157 return t * t * (three - two * t);
158 }
159
160 // ---- Inverse Trigonometry (pure fixed-point) ----------------------------
161
163 constexpr s24x8 one(1.0f);
164 constexpr s24x8 pi_over_2(1.5707963f);
165 bool neg = x.mValue < 0;
166 s24x8 ax = abs(x);
168 if (ax <= one) {
169 result = atan_unit(ax);
170 } else {
171 result = pi_over_2 - atan_unit(one / ax);
172 }
173 return neg ? -result : result;
174 }
175
177 constexpr s24x8 pi(3.1415926f);
178 constexpr s24x8 pi_over_2(1.5707963f);
179 if (x.mValue == 0 && y.mValue == 0) return s24x8();
180 if (x.mValue == 0) return y.mValue > 0 ? pi_over_2 : -pi_over_2;
181 if (y.mValue == 0) return x.mValue > 0 ? s24x8() : pi;
182 s24x8 ax = abs(x);
183 s24x8 ay = abs(y);
184 s24x8 a;
185 if (ax >= ay) {
186 a = atan_unit(ay / ax);
187 } else {
188 a = pi_over_2 - atan_unit(ax / ay);
189 }
190 if (x.mValue < 0) a = pi - a;
191 if (y.mValue < 0) a = -a;
192 return a;
193 }
194
196 constexpr s24x8 one(1.0f);
197 return atan2(x, sqrt(one - x * x));
198 }
199
201 constexpr s24x8 one(1.0f);
202 return atan2(sqrt(one - x * x), x);
203 }
204
206 return x.mValue <= 0 ? s24x8() : from_raw(static_cast<i32>(
207 fl::isqrt64(static_cast<u64>(x.mValue) << FRAC_BITS)));
208 }
209
211 return sqrt(x).mValue == 0
212 ? s24x8()
213 : from_raw(SCALE) / sqrt(x);
214 }
215
217 if (base.mValue <= 0) return s24x8();
218 constexpr s24x8 one(1.0f);
219 if (exp.mValue == 0) return one;
220 if (base == one) return one;
221 // Snap base values within ~2 ULPs of 1.0 to exactly 1.0 to dodge the
222 // log2(1+t) minimax polynomial's upper-endpoint residual (#2969).
223 constexpr i32 kOneRaw = static_cast<i32>(SCALE);
224 if (base.mValue >= (kOneRaw - 2) && base.mValue <= kOneRaw) {
225 return one;
226 }
227 return exp2_fp(exp * log2_fp(base));
228 }
229
230 // ---- Member function versions (operate on *this) -----------------------
231
233 return floor(*this);
234 }
235
237 return ceil(*this);
238 }
239
241 return fract(*this);
242 }
243
245 return abs(*this);
246 }
247
248 constexpr FASTLED_FORCE_INLINE int sign() const FL_NOEXCEPT {
249 return sign(*this);
250 }
251
253 return sin(*this);
254 }
255
257 return cos(*this);
258 }
259
261 return atan(*this);
262 }
263
265 return asin(*this);
266 }
267
269 return acos(*this);
270 }
271
273 return sqrt(*this);
274 }
275
277 return rsqrt(*this);
278 }
279
280 // ---- Trigonometry ------------------------------------------------------
281
283 return from_raw(fl::sin32(angle_to_a24(angle)) >> (31 - FRAC_BITS));
284 }
285
287 return from_raw(fl::cos32(angle_to_a24(angle)) >> (31 - FRAC_BITS));
288 }
289
290 // Combined sin+cos from s24x8 radians. Output in s24x8 [-1, 1].
291 static FASTLED_FORCE_INLINE void sincos(s24x8 angle, s24x8 &out_sin,
292 s24x8 &out_cos) FL_NOEXCEPT {
293 u32 a24 = angle_to_a24(angle);
294 out_sin = from_raw(fl::sin32(a24) >> (31 - FRAC_BITS));
295 out_cos = from_raw(fl::cos32(a24) >> (31 - FRAC_BITS));
296 }
297
298 private:
299 i32 mValue = 0;
300
301 // Returns 0-based position of highest set bit, or -1 if v==0.
302 static constexpr FASTLED_FORCE_INLINE int highest_bit(u32 v) FL_NOEXCEPT {
303 return v == 0 ? -1 : _highest_bit_step(v, 0);
304 }
305
306 static constexpr int _highest_bit_step(u32 v, int r) FL_NOEXCEPT {
307 return (v & 0xFFFF0000u) ? _highest_bit_step(v >> 16, r + 16)
308 : (v & 0x0000FF00u) ? _highest_bit_step(v >> 8, r + 8)
309 : (v & 0x000000F0u) ? _highest_bit_step(v >> 4, r + 4)
310 : (v & 0x0000000Cu) ? _highest_bit_step(v >> 2, r + 2)
311 : (v & 0x00000002u) ? r + 1
312 : r;
313 }
314
315 // Fixed-point log base 2 for positive values.
316 // Uses 4-term minimax polynomial for log2(1+t), t in [0,1).
317 // Horner evaluation uses i64 intermediates (16 frac bits) to minimize
318 // rounding error, then converts back to 8 frac bits.
320 u32 val = static_cast<u32>(x.mValue);
321 int msb = highest_bit(val);
322 i32 int_part = msb - FRAC_BITS;
323 i32 t;
324 if (msb >= FRAC_BITS) {
325 t = static_cast<i32>(
326 (val >> (msb - FRAC_BITS)) - (SCALE));
327 } else {
328 t = static_cast<i32>(
329 (val << (FRAC_BITS - msb)) - (SCALE));
330 }
331 // 4-term minimax coefficients for log2(1+t), t in [0,1).
332 // Stored as i64 with 16 fractional bits.
333 constexpr int IFRAC = 16;
334 constexpr i64 c0 = 94528LL; // 1.44179 * 2^16
335 constexpr i64 c1 = -45814LL; // -0.69907 * 2^16
336 constexpr i64 c2 = 23821LL; // 0.36348 * 2^16
337 constexpr i64 c3 = -6986LL; // -0.10660 * 2^16
338 // Extend t from 8 to 16 frac bits.
339 i64 t16 = static_cast<i64>(t) << (IFRAC - FRAC_BITS);
340 // Horner: t * (c0 + t * (c1 + t * (c2 + t * c3)))
341 i64 acc = c3;
342 acc = c2 + ((acc * t16) >> IFRAC);
343 acc = c1 + ((acc * t16) >> IFRAC);
344 acc = c0 + ((acc * t16) >> IFRAC);
345 i64 frac_part = (acc * t16) >> IFRAC;
346 // Convert from 16 frac bits back to 8.
347 i32 frac8 = static_cast<i32>(frac_part >> (IFRAC - FRAC_BITS));
348 return from_raw(static_cast<i32>(static_cast<u32>(int_part) << FRAC_BITS) + frac8);
349 }
350
351 // Fixed-point 2^x. Uses 4-term minimax polynomial for 2^t, t in [0,1).
352 // Horner evaluation uses i64 intermediates (16 frac bits) to minimize
353 // rounding error, then converts back to 8 frac bits.
355 s24x8 fl_val = floor(x);
356 s24x8 fr = x - fl_val;
357 i32 n = fl_val.mValue >> FRAC_BITS;
358 if (n >= INT_BITS - 1) return from_raw(0x7FFFFFFF);
359 if (n < -FRAC_BITS) return s24x8();
360 i32 int_pow = 0;
361 if (n >= 0) {
362 int_pow = static_cast<i32>(SCALE) << n;
363 } else {
364 int_pow = static_cast<i32>(SCALE) >> (-n);
365 }
366 // 4-term minimax coefficients for 2^t - 1, t in [0,1).
367 // Stored as i64 with 16 fractional bits.
368 constexpr int IFRAC = 16;
369 constexpr i64 d0 = 45427LL; // 0.69316 * 2^16
370 constexpr i64 d1 = 15775LL; // 0.24071 * 2^16
371 constexpr i64 d2 = 3497LL; // 0.05336 * 2^16
372 constexpr i64 d3 = 836LL; // 0.01276 * 2^16
373 // Extend fr from 8 to 16 frac bits.
374 i64 fr16 = static_cast<i64>(fr.mValue) << (IFRAC - FRAC_BITS);
375 // Horner: 1 + fr * (d0 + fr * (d1 + fr * (d2 + fr * d3)))
376 i64 acc = d3;
377 acc = d2 + ((acc * fr16) >> IFRAC);
378 acc = d1 + ((acc * fr16) >> IFRAC);
379 acc = d0 + ((acc * fr16) >> IFRAC);
380 constexpr i64 one16 = 1LL << IFRAC;
381 i64 frac_pow16 = one16 + ((acc * fr16) >> IFRAC);
382 // Convert from 16 frac bits to 8 frac bits, then scale by int_pow.
383 i32 frac_pow8 = static_cast<i32>(frac_pow16 >> (IFRAC - FRAC_BITS));
384 i64 result =
385 (static_cast<i64>(int_pow) * frac_pow8) >> FRAC_BITS;
386 return from_raw(static_cast<i32>(result));
387 }
388
389 // Converts s24x8 radians to sin32/cos32 input format.
390 // 2^24/(2*PI) — converts radians to sin32/cos32 format.
391 static constexpr i32 RAD_TO_24 = 2670177;
393 return static_cast<u32>(
394 (static_cast<i64>(angle.mValue) * RAD_TO_24) >> FRAC_BITS);
395 }
396
397 // Polynomial atan for t in [0, 1]. Returns [0, π/4].
398 // 7th-order minimax: atan(t) ≈ t * (c0 + t² * (c1 + t² * (c2 + t² * c3)))
399 // Coefficients optimized via coordinate descent on s16x16 quantization grid.
401 constexpr s24x8 c0(0.9998779297f);
402 constexpr s24x8 c1(-0.3269348145f);
403 constexpr s24x8 c2(0.1594085693f);
404 constexpr s24x8 c3(-0.0472106934f);
405 s24x8 t2 = t * t;
406 return t * (c0 + t2 * (c1 + t2 * (c2 + t2 * c3)));
407 }
408};
409
410} // namespace fl
411
static constexpr FASTLED_FORCE_INLINE s24x8 ceil(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:122
static FASTLED_FORCE_INLINE s24x8 atan2(s24x8 y, s24x8 x) FL_NOEXCEPT
Definition s24x8.h:176
static constexpr FASTLED_FORCE_INLINE s24x8 lerp(s24x8 a, s24x8 b, s24x8 t) FL_NOEXCEPT
Definition s24x8.h:139
static FASTLED_FORCE_INLINE s24x8 exp2_fp(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:354
static constexpr FASTLED_FORCE_INLINE int highest_bit(u32 v) FL_NOEXCEPT
Definition s24x8.h:302
static FASTLED_FORCE_INLINE s24x8 acos(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:200
FASTLED_FORCE_INLINE s24x8 sin() const FL_NOEXCEPT
Definition s24x8.h:252
constexpr FASTLED_FORCE_INLINE s24x8 operator+(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:75
static constexpr FASTLED_FORCE_INLINE s24x8 sqrt(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:205
static constexpr FASTLED_FORCE_INLINE int sign(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:135
static FASTLED_FORCE_INLINE void sincos(s24x8 angle, s24x8 &out_sin, s24x8 &out_cos) FL_NOEXCEPT
Definition s24x8.h:291
static constexpr i32 RAD_TO_24
Definition s24x8.h:391
constexpr float to_float() const FL_NOEXCEPT
Definition s24x8.h:61
constexpr FASTLED_FORCE_INLINE s24x8 operator*(i32 scalar) const FL_NOEXCEPT
Definition s24x8.h:95
constexpr bool operator==(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:109
constexpr FASTLED_FORCE_INLINE s24x8 operator-() const FL_NOEXCEPT
Definition s24x8.h:85
static constexpr FASTLED_FORCE_INLINE s24x8 floor(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:118
constexpr s24x8() FL_NOEXCEPT=default
static FASTLED_FORCE_INLINE s24x8 smoothstep(s24x8 edge0, s24x8 edge1, s24x8 x) FL_NOEXCEPT
Definition s24x8.h:151
static FASTLED_FORCE_INLINE s24x8 cos(s24x8 angle) FL_NOEXCEPT
Definition s24x8.h:286
FASTLED_FORCE_INLINE s24x8 atan() const FL_NOEXCEPT
Definition s24x8.h:260
constexpr FASTLED_FORCE_INLINE s24x8 rsqrt() const FL_NOEXCEPT
Definition s24x8.h:276
static constexpr FASTLED_FORCE_INLINE u32 angle_to_a24(s24x8 angle) FL_NOEXCEPT
Definition s24x8.h:392
static constexpr FASTLED_FORCE_INLINE s24x8 step(s24x8 edge, s24x8 x) FL_NOEXCEPT
Definition s24x8.h:147
friend constexpr s24x8 operator*(i32 scalar, s24x8 fp) FL_NOEXCEPT
Definition s24x8.h:99
constexpr s24x8(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 s24x8.h:40
constexpr bool operator<(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:105
i32 mValue
Definition s24x8.h:299
static constexpr FASTLED_FORCE_INLINE s24x8 from_raw(i32 raw) FL_NOEXCEPT
Definition s24x8.h:53
constexpr FASTLED_FORCE_INLINE int sign() const FL_NOEXCEPT
Definition s24x8.h:248
constexpr FASTLED_FORCE_INLINE s24x8 operator*(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:65
constexpr s24x8(IntT n) FL_NOEXCEPT
Definition s24x8.h:35
static constexpr int _highest_bit_step(u32 v, int r) FL_NOEXCEPT
Definition s24x8.h:306
static FASTLED_FORCE_INLINE s24x8 sin(s24x8 angle) FL_NOEXCEPT
Definition s24x8.h:282
constexpr bool operator>=(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:108
static FASTLED_FORCE_INLINE s24x8 atan_unit(s24x8 t) FL_NOEXCEPT
Definition s24x8.h:400
constexpr i32 to_int() const FL_NOEXCEPT
Definition s24x8.h:60
FASTLED_FORCE_INLINE s24x8 cos() const FL_NOEXCEPT
Definition s24x8.h:256
static FASTLED_FORCE_INLINE s24x8 log2_fp(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:319
static constexpr FASTLED_FORCE_INLINE s24x8 mod(s24x8 a, s24x8 b) FL_NOEXCEPT
Definition s24x8.h:114
static FASTLED_FORCE_INLINE s24x8 asin(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:195
static constexpr FASTLED_FORCE_INLINE s24x8 fract(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:127
static constexpr i32 SCALE
Definition s24x8.h:23
constexpr FASTLED_FORCE_INLINE s24x8 operator-(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:80
static FASTLED_FORCE_INLINE s24x8 atan(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:162
static constexpr FASTLED_FORCE_INLINE s24x8 abs(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:131
static constexpr int INT_BITS
Definition s24x8.h:21
constexpr FASTLED_FORCE_INLINE s24x8 operator>>(int shift) const FL_NOEXCEPT
Definition s24x8.h:89
static FASTLED_FORCE_INLINE s24x8 pow(s24x8 base, s24x8 exp) FL_NOEXCEPT
Definition s24x8.h:216
constexpr i32 raw() const FL_NOEXCEPT
Definition s24x8.h:59
constexpr FASTLED_FORCE_INLINE s24x8 sqrt() const FL_NOEXCEPT
Definition s24x8.h:272
FASTLED_FORCE_INLINE s24x8 acos() const FL_NOEXCEPT
Definition s24x8.h:268
static constexpr int FRAC_BITS
Definition s24x8.h:22
constexpr FASTLED_FORCE_INLINE s24x8 fract() const FL_NOEXCEPT
Definition s24x8.h:240
static constexpr FASTLED_FORCE_INLINE s24x8 rsqrt(s24x8 x) FL_NOEXCEPT
Definition s24x8.h:210
constexpr bool operator>(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:106
constexpr FASTLED_FORCE_INLINE s24x8 ceil() const FL_NOEXCEPT
Definition s24x8.h:236
constexpr s24x8(i32 raw, RawTag) FL_NOEXCEPT
Definition s24x8.h:51
static constexpr FASTLED_FORCE_INLINE s24x8 clamp(s24x8 x, s24x8 lo, s24x8 hi) FL_NOEXCEPT
Definition s24x8.h:143
constexpr FASTLED_FORCE_INLINE s24x8 floor() const FL_NOEXCEPT
Definition s24x8.h:232
constexpr bool operator!=(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:110
constexpr FASTLED_FORCE_INLINE s24x8 operator/(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:70
constexpr bool operator<=(s24x8 b) const FL_NOEXCEPT
Definition s24x8.h:107
constexpr FASTLED_FORCE_INLINE s24x8 abs() const FL_NOEXCEPT
Definition s24x8.h:244
FASTLED_FORCE_INLINE s24x8 asin() const FL_NOEXCEPT
Definition s24x8.h:264
#define constexpr
Declares that it is possible to evaluate a value at compile time, introduced in C++11.
Definition cpp_compat.h:15
FASTLED_FORCE_INLINE i32 cos32(u32 angle) FL_NOEXCEPT
Definition sin32.h:81
FASTLED_FORCE_INLINE i32 sin32(u32 angle) FL_NOEXCEPT
Definition sin32.h:59
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