29constexpr q31_t ONE_Q31{2147483647};
30constexpr float ONE_Q31f{2147483647.0f};
31constexpr q31_t ONE_Q15{65536};
32constexpr q31_t NEGATIVE_ONE_Q31{-2147483648};
33constexpr q31_t ONE_OVER_SQRT2_Q31{1518500250};
36static inline q31_t toPositive(q31_t a) __attribute__((always_inline, unused));
37static inline q31_t toPositive(q31_t a) {
38 return ((a / 2) + (1073741824));
45static inline q31_t multiply_32x32_rshift32(q31_t a, q31_t b) __attribute__((always_inline, unused));
46static inline q31_t multiply_32x32_rshift32(q31_t a, q31_t b) {
48 asm(
"smmul %0, %1, %2" :
"=r"(out) :
"r"(a),
"r"(b));
53static inline q31_t multiply_32x32_rshift32_rounded(q31_t a, q31_t b) __attribute__((always_inline, unused));
54static inline q31_t multiply_32x32_rshift32_rounded(q31_t a, q31_t b) {
56 asm(
"smmulr %0, %1, %2" :
"=r"(out) :
"r"(a),
"r"(b));
62static inline q31_t q31_mult(q31_t a, q31_t b) __attribute__((always_inline, unused));
63static inline q31_t q31_mult(q31_t a, q31_t b) {
65 asm(
"smmul %0, %1, %2" :
"=r"(out) :
"r"(a),
"r"(b));
70static inline q31_t q31tRescale(q31_t a, uint32_t proportion) __attribute__((always_inline, unused));
71static inline q31_t q31tRescale(q31_t a, uint32_t proportion) {
73 asm(
"smmul %0, %1, %2" :
"=r"(out) :
"r"(a),
"r"(proportion));
78static inline q31_t multiply_accumulate_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b)
79 __attribute__((always_inline, unused));
80static inline q31_t multiply_accumulate_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b) {
82 asm(
"smmlar %0, %1, %2, %3" :
"=r"(out) :
"r"(a),
"r"(b),
"r"(sum));
87static inline q31_t multiply_accumulate_32x32_rshift32(q31_t sum, q31_t a, q31_t b)
88 __attribute__((always_inline, unused));
89static inline q31_t multiply_accumulate_32x32_rshift32(q31_t sum, q31_t a, q31_t b) {
91 asm(
"smmla %0, %1, %2, %3" :
"=r"(out) :
"r"(a),
"r"(b),
"r"(sum));
96static inline q31_t multiply_subtract_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b)
97 __attribute__((always_inline, unused));
98static inline q31_t multiply_subtract_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b) {
100 asm(
"smmlsr %0, %1, %2, %3" :
"=r"(out) :
"r"(a),
"r"(b),
"r"(sum));
105template <u
int8_t bits>
106static inline int32_t signed_saturate(int32_t val) __attribute__((always_inline, unused));
107template <u
int8_t bits>
108static inline int32_t signed_saturate(int32_t val) {
110 asm(
"ssat %0, %1, %2" :
"=r"(out) :
"I"(bits),
"r"(val));
114static inline int32_t add_saturate(int32_t a, int32_t b) __attribute__((always_inline, unused));
115static inline int32_t add_saturate(int32_t a, int32_t b) {
117 asm(
"qadd %0, %1, %2" :
"=r"(out) :
"r"(a),
"r"(b));
121static inline int32_t subtract_saturate(int32_t a, int32_t b) __attribute__((always_inline, unused));
122static inline int32_t subtract_saturate(int32_t a, int32_t b) {
124 asm(
"qsub %0, %1, %2" :
"=r"(out) :
"r"(a),
"r"(b));
128inline int32_t clz(uint32_t input) {
130 asm(
"clz %0, %1" :
"=r"(out) :
"r"(input));
136static inline q31_t q31_from_float(
float value) {
137 asm(
"vcvt.s32.f32 %0, %0, #31" :
"=t"(value) :
"t"(value));
138 return std::bit_cast<q31_t>(value);
143static inline float q31_to_float(q31_t value) {
144 asm(
"vcvt.f32.s32 %0, %0, #31" :
"=t"(value) :
"t"(value));
145 return std::bit_cast<float>(value);
149static inline q31_t multiply_32x32_rshift32(q31_t a, q31_t b) {
150 return (int32_t)(((int64_t)a * b) >> 32);
154static inline q31_t multiply_32x32_rshift32_rounded(q31_t a, q31_t b) {
155 return (int32_t)(((int64_t)a * b + 0x80000000) >> 32);
159static inline q31_t multiply_accumulate_32x32_rshift32(q31_t sum, q31_t a, q31_t b) {
160 return (int32_t)(((((int64_t)sum) << 32) + ((int64_t)a * b)) >> 32);
164static inline q31_t multiply_accumulate_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b) {
165 return (int32_t)(((((int64_t)sum) << 32) + ((int64_t)a * b) + 0x80000000) >> 32);
169static inline q31_t multiply_subtract_32x32_rshift32(q31_t sum, q31_t a, q31_t b) {
170 return (int32_t)(((((int64_t)sum) << 32) - ((int64_t)a * b)) >> 32);
174static inline q31_t multiply_subtract_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b) {
175 return (int32_t)((((((int64_t)sum) << 32) - ((int64_t)a * b)) + 0x80000000) >> 32);
179template <u
int8_t bits>
180static inline int32_t signed_saturate(int32_t val) {
181 return std::min(val, 1 << bits);
184static inline int32_t add_saturate(int32_t a, int32_t b) __attribute__((always_inline, unused));
185static inline int32_t add_saturate(int32_t a, int32_t b) {
189static inline int32_t subtract_saturate(int32_t a, int32_t b) __attribute__((always_inline, unused));
190static inline int32_t subtract_saturate(int32_t a, int32_t b) {
194inline int32_t clz(uint32_t input) {
195 return __builtin_clz(input);
198[[gnu::always_inline]]
constexpr q31_t q31_from_float(
float value) {
202 auto bits = std::bit_cast<uint32_t>(value);
205 bool negative = bits & 0x80000000;
208 int32_t exponent =
static_cast<int32_t
>((bits >> 23) & 0xFF) - 127;
210 q31_t output_value = 0;
214 output_value = std::numeric_limits<q31_t>::max();
219 uint32_t mantissa = (bits << 8) | 0x80000000;
220 output_value =
static_cast<q31_t
>(mantissa >> -exponent);
224 return (negative) ? -output_value : output_value;
233template <std::
size_t FractionalBits,
bool Rounded = false,
bool FastApproximation = true>
235 static_assert(FractionalBits > 0,
"FractionalBits must be greater than 0");
236 static_assert(FractionalBits < 32,
"FractionalBits must be less than 32");
238 using BaseType = int32_t;
239 using IntermediateType = int64_t;
243 if constexpr (Rounded) {
244 return multiply_accumulate_32x32_rshift32_rounded(a, b, c);
247 return multiply_accumulate_32x32_rshift32(a, b, c);
252 [[gnu::always_inline]]
static int32_t signed_most_significant_word_multiply(int32_t a, int32_t b) {
253 if constexpr (Rounded) {
254 return multiply_32x32_rshift32_rounded(a, b);
257 return multiply_32x32_rshift32(a, b);
261 static constexpr BaseType one() noexcept {
262 if constexpr (fractional_bits == 31) {
263 return std::numeric_limits<BaseType>::max();
266 return 1 << fractional_bits;
271 constexpr static std::size_t fractional_bits = FractionalBits;
272 constexpr static std::size_t integral_bits = 32 - FractionalBits;
273 constexpr static bool rounded = Rounded;
274 constexpr static bool fast_approximation = FastApproximation;
281 template <std::
size_t OtherFractionalBits>
283 if constexpr (FractionalBits == OtherFractionalBits) {
286 else if constexpr (FractionalBits > OtherFractionalBits) {
288 constexpr int32_t shift = FractionalBits - OtherFractionalBits;
289 value_ = signed_saturate<32 - shift>(value_);
290 value_ = (value_ << shift) + (value_ % 2);
292 else if constexpr (rounded) {
294 constexpr int32_t shift = OtherFractionalBits - FractionalBits;
295 value_ >>= shift + ((1 << shift) - 1);
299 value_ >>= (OtherFractionalBits - FractionalBits);
305 template <std::
integral T>
306 constexpr explicit FixedPoint(T value) noexcept : value_(
static_cast<BaseType
>(value) << fractional_bits) {}
311 if constexpr (std::is_constant_evaluated()) {
312 value *= FixedPoint::one();
314 if constexpr (rounded) {
315 value_ =
static_cast<BaseType
>((value >= 0.0) ? std::ceil(value) : std::floor(value));
318 value_ =
static_cast<BaseType
>(value);
322 asm(
"vcvt.s32.f32 %0, %1, %2" :
"=t"(value) :
"t"(value),
"I"(fractional_bits));
323 value_ = std::bit_cast<int32_t>(value);
329 constexpr explicit operator float() const noexcept {
330 if constexpr (std::is_constant_evaluated()) {
331 return static_cast<float>(value_) / FixedPoint::one();
333 int32_t output = value_;
334 asm(
"vcvt.f32.s32 %0, %1, %2" :
"=t"(output) :
"t"(output),
"I"(fractional_bits));
335 return std::bit_cast<float>(output);
341 if constexpr (std::is_constant_evaluated()) {
342 value *= FixedPoint::one();
344 if constexpr (rounded) {
345 value_ =
static_cast<BaseType
>((value >= 0.0) ? std::ceil(value) : std::floor(value));
348 value_ =
static_cast<BaseType
>(value);
352 auto output = std::bit_cast<int64_t>(value);
353 asm(
"vcvt.s32.f64 %0, %1, %2" :
"=w"(output) :
"w"(output),
"I"(fractional_bits));
354 value_ =
static_cast<BaseType
>(output);
360 explicit operator double() const noexcept {
361 if constexpr (std::is_constant_evaluated()) {
362 return static_cast<double>(value_) / FixedPoint::one();
364 auto output = std::bit_cast<double>((int64_t)value_);
365 asm(
"vcvt.f64.s32 %0, %1, %2" :
"=w"(output) :
"w"(output),
"I"(fractional_bits));
370 template <std::
size_t OutputFractionalBits>
376 template <std::
integral T>
377 explicit operator T() const noexcept {
378 return static_cast<T
>(value_ >> fractional_bits);
381 explicit operator bool() const noexcept {
return value_ != 0; }
387 [[nodiscard]]
constexpr BaseType
raw() const noexcept {
return value_; }
403 value_ = add_saturate(value_, rhs.value_);
410 return from_raw(subtract_saturate(value_, rhs.value_));
416 value_ = subtract_saturate(value_, rhs.value_);
423 if constexpr (fast_approximation && fractional_bits > 16) {
425 constexpr int32_t shift = fractional_bits - ((fractional_bits * 2) - 32);
426 return from_raw(signed_most_significant_word_multiply(value_, rhs.value_) << shift);
429 if constexpr (rounded) {
430 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.value_) >> (fractional_bits - 1);
431 return from_raw(
static_cast<BaseType
>((value >> 1) + (value % 2)));
434 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.value_) >> fractional_bits;
435 return from_raw(
static_cast<BaseType
>(value));
447 template <std::size_t OutputFractionalBits = FractionalBits, std::size_t OtherFractionalBits,
bool OtherRounded,
448 bool OtherApproximating>
449 requires(OtherRounded == Rounded && OtherApproximating == FastApproximation)
452 if constexpr (fast_approximation) {
453 constexpr int32_t l_shift = OutputFractionalBits - ((FractionalBits + OtherFractionalBits) - 32);
454 static_assert(l_shift < 32 && l_shift > -32);
455 BaseType value = signed_most_significant_word_multiply(value_, rhs.
raw());
456 return from_raw(l_shift > 0 ? value << l_shift : value >> -l_shift);
459 constexpr int32_t r_shift = (FractionalBits + OtherFractionalBits) - OutputFractionalBits;
460 if constexpr (rounded) {
461 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.
raw())
463 return from_raw(
static_cast<BaseType
>((value / 2) + (value % 2)));
466 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.
raw()) >> r_shift;
467 return from_raw(
static_cast<BaseType
>(value));
472 template <std::
size_t OtherFractionalBits>
481 if (rhs.value_ == 0) {
482 return from_raw(std::numeric_limits<BaseType>::max());
484 if constexpr (rounded) {
485 IntermediateType value = (
static_cast<IntermediateType
>(value_) << (fractional_bits + 1)) / rhs.value_;
486 return from_raw(
static_cast<BaseType
>((value / 2) + (value % 2)));
489 IntermediateType value = (
static_cast<IntermediateType
>(value_) << fractional_bits) / rhs.value_;
490 return from_raw(
static_cast<BaseType
>(value));
501 template <std::
size_t OtherFractionalBitsA, std::
size_t OtherFractionalBitsB>
506 if constexpr (fast_approximation && (OtherFractionalBitsA + OtherFractionalBitsB) - 32 == FractionalBits) {
509 return *
this +
static_cast<FixedPoint>(a * b);
514 if constexpr (fast_approximation && (((FractionalBits * 2) - 32) == (FractionalBits - 1))) {
515 return from_raw(
static_cast<FixedPoint<FractionalBits - 1
>>(*this).MultiplyAdd(a, b).raw() << 1);
517 return *
this + (a * b);
527 template <std::
size_t OtherFractionalBits>
529 int integral_value = value_ >> fractional_bits;
530 int other_integral_value = rhs.
raw() >> OtherFractionalBits;
531 int fractional_value = value_ & ((1 << fractional_bits) - 1);
532 int other_fractional_value = rhs.
raw() & ((1 << OtherFractionalBits) - 1);
535 if (fractional_bits > OtherFractionalBits) {
536 fractional_value >>= fractional_bits - OtherFractionalBits;
539 other_fractional_value >>= OtherFractionalBits - fractional_bits;
542 return integral_value == other_integral_value && fractional_value == other_fractional_value;
546 template <std::
size_t OtherFractionalBits>
549 int integral_value = value_ >> fractional_bits;
550 int other_integral_value = rhs.
raw() >> OtherFractionalBits;
551 int fractional_value = value_ & ((1 << fractional_bits) - 1);
552 int other_fractional_value = rhs.
raw() & ((1 << OtherFractionalBits) - 1);
555 if (fractional_bits > OtherFractionalBits) {
556 fractional_value >>= fractional_bits - OtherFractionalBits;
559 other_fractional_value >>= OtherFractionalBits - fractional_bits;
562 if (integral_value < other_integral_value) {
563 return std::strong_ordering::less;
565 if (integral_value > other_integral_value) {
566 return std::strong_ordering::greater;
568 if (fractional_value < other_fractional_value) {
569 return std::strong_ordering::less;
571 if (fractional_value > other_fractional_value) {
572 return std::strong_ordering::greater;
574 return std::strong_ordering::equal;
578 template <
typename T>
579 requires std::integral<T> || std::floating_point<T>
Fixed point number with a configurable number of fractional bits.
Definition fixedpoint.h:234
constexpr bool operator==(const FixedPoint &rhs) const noexcept
Equality operator.
Definition fixedpoint.h:521
constexpr FixedPoint operator*=(const FixedPoint< OtherFractionalBits > &rhs)
Multiplication operator Multiply two fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:473
constexpr FixedPoint(float value) noexcept
Convert from a float to a fixed point number.
Definition fixedpoint.h:310
constexpr std::strong_ordering operator<=>(const FixedPoint &rhs) const noexcept
Three-way comparison operator.
Definition fixedpoint.h:524
constexpr FixedPoint operator/(const FixedPoint &rhs) const
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:480
constexpr FixedPoint(T value) noexcept
Convert an integer to a fixed point number.
Definition fixedpoint.h:306
constexpr FixedPoint< OutputFractionalBits > as() const
Convert to a fixed point number with a different number of fractional bits.
Definition fixedpoint.h:371
constexpr FixedPoint MultiplyAdd(const FixedPoint< OtherFractionalBitsA > &a, const FixedPoint< OtherFractionalBitsB > &b) const
Fused multiply-add operation for fixed point numbers with a different number of fractional bits.
Definition fixedpoint.h:502
constexpr FixedPoint operator/=(const FixedPoint &rhs)
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:495
static int32_t signed_most_significant_word_multiply_add(int32_t a, int32_t b, int32_t c)
a + b * c
Definition fixedpoint.h:242
constexpr bool operator==(const FixedPoint< OtherFractionalBits > &rhs) const noexcept
Equality operator for fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:528
constexpr FixedPoint(FixedPoint< OtherFractionalBits > other) noexcept
Construct a fixed point number from another fixed point number.
Definition fixedpoint.h:282
constexpr FixedPoint operator+(const FixedPoint &rhs) const
Addition operator Add two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:398
constexpr FixedPoint operator-() const
Negation operator.
Definition fixedpoint.h:384
constexpr FixedPoint operator*(const FixedPoint &rhs) const
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:422
constexpr BaseType raw() const noexcept
Get the internal value.
Definition fixedpoint.h:387
constexpr std::strong_ordering operator<=>(const FixedPoint< OtherFractionalBits > &rhs) const noexcept
Three-way comparison operator for fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:547
static constexpr FixedPoint from_raw(BaseType raw) noexcept
Construct from a raw value.
Definition fixedpoint.h:390
constexpr FixedPoint operator-(const FixedPoint &rhs) const
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:409
constexpr FixedPoint operator*=(const FixedPoint &rhs)
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:440
constexpr FixedPoint(double value) noexcept
Convert from a double to a fixed point number.
Definition fixedpoint.h:340
constexpr FixedPoint operator+=(const FixedPoint &rhs)
Addition operator Add two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:402
constexpr FixedPoint MultiplyAdd(const FixedPoint &a, const FixedPoint &b) const
Fused multiply-add operation for fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:513
constexpr bool operator==(const T &rhs) const noexcept
Equality operator for integers and floating point numbers.
Definition fixedpoint.h:580
constexpr FixedPoint operator-=(const FixedPoint &rhs)
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:415
constexpr FixedPoint()=default
Default constructor.