FastLED 3.9.15
Loading...
Searching...
No Matches
s0x32.h
Go to the documentation of this file.
1#pragma once
2
3// Signed 0.32 fixed-point arithmetic.
4// Represents normalized values in range [-1.0, 1.0].
5
6#include "fl/stl/int.h"
9#include "fl/stl/noexcept.h"
10#include "fl/stl/undef.h" // Undefine abs/min/max macros from Arduino.h
11
13
14namespace fl {
15
16// Forward declaration for cross-type operations
17class s16x16;
18
19// Signed 0.32 fixed-point value type (Q31 format in DSP terminology).
20// Represents values in range [-1.0, 1.0] using all 32 bits for fractional precision.
21//
22// Bit layout (i32 storage, two's complement):
23// Bit 31: Sign bit (implicit in two's complement)
24// Bits 30-0: Fractional magnitude (31 bits of precision)
25// Value interpretation: raw_i32 / 2^31
26//
27// Primary use cases:
28// - sin32/cos32 output (normalized trigonometric values)
29// - Color scaling factors
30// - Normalized coordinate systems
31class s0x32 {
32 public:
33 static constexpr int INT_BITS = 0; // No integer bits (always in [-1, 1])
34 static constexpr int FRAC_BITS = 32; // 32 fractional bits (all bits)
35
36 // ---- Construction ------------------------------------------------------
37
38 constexpr s0x32() FL_NOEXCEPT = default;
39
40 // Construct from float (clamps to [-1.0, 1.0] range)
41 // Q31 format: max value is 0x7FFFFFFF (just under 1.0), min is 0x80000000 (-1.0)
42 explicit constexpr s0x32(float f) FL_NOEXCEPT
43 : mValue(f <= -1.0f ? (i32)0x80000000 : // Exactly -1.0
44 f >= 1.0f ? (i32)0x7FFFFFFF : // Max positive (0.9999999995...)
45 static_cast<i32>(f * 2147483648.0f)) {}
46
47 // Auto-promotion from other fixed-point types
48 // s0x32 has INT_BITS=0, so it can only accept types with INT_BITS=0
49 // and FRAC_BITS ≤ 32 (but since s0x32 has the most fractional precision, no other type qualifies)
50 // This constructor allows future expansion if more normalized types are added
51 template <typename OtherFP>
52 constexpr s0x32(const OtherFP& other,
53 typename fl::enable_if<
54 (OtherFP::INT_BITS <= INT_BITS) &&
55 (OtherFP::FRAC_BITS <= FRAC_BITS) &&
56 (OtherFP::INT_BITS != INT_BITS || OtherFP::FRAC_BITS != FRAC_BITS),
57 int>::type = 0)
58 FL_NOEXCEPT : mValue(static_cast<i32>(
59 static_cast<i64>(other.raw()) << (FRAC_BITS - OtherFP::FRAC_BITS))) {}
60
61 // Construct from raw i32 value (Q31 format)
62 // Raw constructor for C++11 constexpr from_raw
63 struct RawTag {};
64 constexpr explicit s0x32(i32 raw, RawTag) FL_NOEXCEPT : mValue(raw) {}
65
67 return s0x32(raw, RawTag());
68 }
69
70 // ---- Access ------------------------------------------------------------
71
72 constexpr i32 raw() const FL_NOEXCEPT { return mValue; }
73
74 // Convert to integer (always 0 or -1 since range is [-1.0, 1.0])
75 constexpr i32 to_int() const FL_NOEXCEPT { return mValue >> 31; }
76
77 constexpr float to_float() const FL_NOEXCEPT {
78 return static_cast<float>(mValue) / (1LL << 31);
79 }
80
81 // ---- Same-type arithmetic (s0x32 OP s0x32 → s0x32) --------------------
82
84 return from_raw(static_cast<i32>(
85 static_cast<u32>(mValue) + static_cast<u32>(b.mValue)));
86 }
87
89 return from_raw(static_cast<i32>(
90 static_cast<u32>(mValue) - static_cast<u32>(b.mValue)));
91 }
92
94 return from_raw(static_cast<i32>(0u - static_cast<u32>(mValue)));
95 }
96
97 // Multiply two normalized values: s0x32 × s0x32 → s0x32
98 // Both inputs ≤ 1.0, so product ≤ 1.0
100 // Q31 × Q31 = Q62 → shift right 31 → Q31
101 return from_raw(static_cast<i32>(
102 (static_cast<i64>(mValue) * b.mValue) >> 31));
103 }
104
105 // Divide normalized values: s0x32 / s0x32 → s0x32
107 // Q31 / Q31: shift dividend left 31 bits then divide
108 // (a / 2^31) / (b / 2^31) = a / b → need (a << 31) / b
109 return from_raw(static_cast<i32>(
110 (static_cast<i64>(mValue) << 31) / b.mValue));
111 }
112
114 return from_raw(mValue >> shift);
115 }
116
118 return from_raw(mValue << shift);
119 }
120
121 // ---- Scalar arithmetic (s0x32 × raw integer → s0x32) ------------------
122
123 constexpr FASTLED_FORCE_INLINE s0x32 operator*(i32 scalar) const FL_NOEXCEPT {
124 // Q31 * scalar with clamping to prevent overflow
125 return (static_cast<i64>(mValue) * scalar > 0x7FFFFFFFLL)
126 ? from_raw(0x7FFFFFFF)
127 : (static_cast<i64>(mValue) * scalar < -0x80000000LL)
128 ? from_raw(static_cast<i32>(0x80000000u))
129 : from_raw(static_cast<i32>(static_cast<i64>(mValue) * scalar));
130 }
131
132 friend constexpr s0x32 operator*(i32 scalar, s0x32 a) FL_NOEXCEPT {
133 return a * scalar; // Commutative
134 }
135
136 constexpr FASTLED_FORCE_INLINE s0x32 operator/(i32 scalar) const FL_NOEXCEPT {
137 return from_raw(mValue / scalar);
138 }
139
140 // ---- Cross-type operations (s0x32 × s16x16 → s16x16) ------------------
141
142 // Multiply normalized value (s0x32) by general fixed-point (s16x16)
143 // Common pattern: sin/cos × distance
144 // Math: Q31 × Q16 = Q47 → shift right 31 → Q16
145 // Implemented in fixed_point.h after s16x16 is fully defined
147
148 friend constexpr s16x16 operator*(s16x16 a, s0x32 b) FL_NOEXCEPT;
149
150 // ---- Math functions ----------------------------------------------------
151
153 return from_raw(x.mValue < 0 ? -x.mValue : x.mValue);
154 }
155
157 return from_raw(a.mValue < b.mValue ? a.mValue : b.mValue);
158 }
159
161 return from_raw(a.mValue > b.mValue ? a.mValue : b.mValue);
162 }
163
164 // ---- Comparisons -------------------------------------------------------
165
166 constexpr bool operator<(s0x32 b) const FL_NOEXCEPT { return mValue < b.mValue; }
167 constexpr bool operator>(s0x32 b) const FL_NOEXCEPT { return mValue > b.mValue; }
168 constexpr bool operator<=(s0x32 b) const FL_NOEXCEPT { return mValue <= b.mValue; }
169 constexpr bool operator>=(s0x32 b) const FL_NOEXCEPT { return mValue >= b.mValue; }
170 constexpr bool operator==(s0x32 b) const FL_NOEXCEPT { return mValue == b.mValue; }
171 constexpr bool operator!=(s0x32 b) const FL_NOEXCEPT { return mValue != b.mValue; }
172
173 private:
174 i32 mValue = 0;
175};
176
177} // namespace fl
178
constexpr i32 raw() const FL_NOEXCEPT
Definition s0x32.h:72
constexpr bool operator>=(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:169
constexpr bool operator<=(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:168
constexpr FASTLED_FORCE_INLINE s0x32 operator>>(int shift) const FL_NOEXCEPT
Definition s0x32.h:113
constexpr bool operator==(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:170
constexpr FASTLED_FORCE_INLINE s16x16 operator*(s16x16 b) const FL_NOEXCEPT
static constexpr FASTLED_FORCE_INLINE s0x32 max(s0x32 a, s0x32 b) FL_NOEXCEPT
Definition s0x32.h:160
constexpr bool operator!=(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:171
constexpr bool operator<(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:166
static constexpr FASTLED_FORCE_INLINE s0x32 from_raw(i32 raw) FL_NOEXCEPT
Definition s0x32.h:66
static constexpr FASTLED_FORCE_INLINE s0x32 min(s0x32 a, s0x32 b) FL_NOEXCEPT
Definition s0x32.h:156
i32 mValue
Definition s0x32.h:174
constexpr FASTLED_FORCE_INLINE s0x32 operator+(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:83
constexpr i32 to_int() const FL_NOEXCEPT
Definition s0x32.h:75
constexpr FASTLED_FORCE_INLINE s0x32 operator/(i32 scalar) const FL_NOEXCEPT
Definition s0x32.h:136
constexpr float to_float() const FL_NOEXCEPT
Definition s0x32.h:77
constexpr s0x32(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 s0x32.h:52
constexpr FASTLED_FORCE_INLINE s0x32 operator*(i32 scalar) const FL_NOEXCEPT
Definition s0x32.h:123
static constexpr int FRAC_BITS
Definition s0x32.h:34
constexpr bool operator>(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:167
constexpr FASTLED_FORCE_INLINE s0x32 operator<<(int shift) const FL_NOEXCEPT
Definition s0x32.h:117
constexpr s0x32(i32 raw, RawTag) FL_NOEXCEPT
Definition s0x32.h:64
static constexpr int INT_BITS
Definition s0x32.h:33
constexpr FASTLED_FORCE_INLINE s0x32 operator/(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:106
constexpr FASTLED_FORCE_INLINE s0x32 operator-() const FL_NOEXCEPT
Definition s0x32.h:93
static constexpr FASTLED_FORCE_INLINE s0x32 abs(s0x32 x) FL_NOEXCEPT
Definition s0x32.h:152
constexpr FASTLED_FORCE_INLINE s0x32 operator-(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:88
constexpr s0x32() FL_NOEXCEPT=default
constexpr FASTLED_FORCE_INLINE s0x32 operator*(s0x32 b) const FL_NOEXCEPT
Definition s0x32.h:99
friend constexpr s0x32 operator*(i32 scalar, s0x32 a) FL_NOEXCEPT
Definition s0x32.h:132
#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
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