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));
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));
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);
160static inline q31_t q31_mult(q31_t a, q31_t b) {
161 return multiply_32x32_rshift32(a, b) * 2;
166static inline q31_t q31tRescale(q31_t a, uint32_t proportion) {
167 return multiply_32x32_rshift32(a, (q31_t)proportion);
175static inline q31_t multiply_accumulate_32x32_rshift32(q31_t sum, q31_t a, q31_t b) {
176 return (q31_t)(sum + (((int64_t)a * b) >> 32));
180static inline q31_t multiply_accumulate_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b) {
181 return (q31_t)(sum + (((int64_t)a * b + 0x80000000) >> 32));
185static inline q31_t multiply_subtract_32x32_rshift32(q31_t sum, q31_t a, q31_t b) {
186 return (q31_t)(sum + ((-((int64_t)a * b)) >> 32));
190static inline q31_t multiply_subtract_32x32_rshift32_rounded(q31_t sum, q31_t a, q31_t b) {
191 return (q31_t)(sum + ((0x80000000LL - (int64_t)a * b) >> 32));
197template <u
int8_t bits>
198static inline int32_t signed_saturate(int32_t val) {
199 constexpr int32_t hi =
static_cast<int32_t
>((
static_cast<uint32_t
>(1) << (bits - 1)) - 1);
200 constexpr int32_t lo = -hi - 1;
201 return val > hi ? hi : (val < lo ? lo : val);
206static inline int32_t add_saturate(int32_t a, int32_t b) __attribute__((always_inline, unused));
207static inline int32_t add_saturate(int32_t a, int32_t b) {
208 int64_t r =
static_cast<int64_t
>(a) + b;
209 return r > INT32_MAX ? INT32_MAX : (r < INT32_MIN ? INT32_MIN : static_cast<int32_t>(r));
213static inline int32_t subtract_saturate(int32_t a, int32_t b) __attribute__((always_inline, unused));
214static inline int32_t subtract_saturate(int32_t a, int32_t b) {
215 int64_t r =
static_cast<int64_t
>(a) - b;
216 return r > INT32_MAX ? INT32_MAX : (r < INT32_MIN ? INT32_MIN : static_cast<int32_t>(r));
219inline int32_t clz(uint32_t input) {
221 return input ? __builtin_clz(input) : 32;
224[[gnu::always_inline]]
constexpr q31_t q31_from_float(
float value) {
228 auto bits = std::bit_cast<uint32_t>(value);
231 bool negative = bits & 0x80000000;
234 int32_t exponent =
static_cast<int32_t
>((bits >> 23) & 0xFF) - 127;
238 return negative ? std::numeric_limits<q31_t>::min() : std::numeric_limits<q31_t>::max();
243 int32_t shift = -exponent;
249 uint32_t mantissa = (bits << 8) | 0x80000000;
250 q31_t output_value =
static_cast<q31_t
>(mantissa >> shift);
251 return (negative) ? -output_value : output_value;
255static inline float q31_to_float(q31_t value) {
256 return static_cast<float>(value) / 2147483648.0f;
265template <std::
size_t FractionalBits,
bool Rounded = false,
bool FastApproximation = true>
267 static_assert(FractionalBits > 0,
"FractionalBits must be greater than 0");
268 static_assert(FractionalBits < 32,
"FractionalBits must be less than 32");
270 using BaseType = int32_t;
271 using IntermediateType = int64_t;
275 if constexpr (Rounded) {
276 return multiply_accumulate_32x32_rshift32_rounded(a, b, c);
279 return multiply_accumulate_32x32_rshift32(a, b, c);
284 [[gnu::always_inline]]
static int32_t signed_most_significant_word_multiply(int32_t a, int32_t b) {
285 if constexpr (Rounded) {
286 return multiply_32x32_rshift32_rounded(a, b);
289 return multiply_32x32_rshift32(a, b);
293 static constexpr BaseType one() noexcept {
294 if constexpr (fractional_bits == 31) {
295 return std::numeric_limits<BaseType>::max();
298 return 1 << fractional_bits;
303 constexpr static std::size_t fractional_bits = FractionalBits;
304 constexpr static std::size_t integral_bits = 32 - FractionalBits;
305 constexpr static bool rounded = Rounded;
306 constexpr static bool fast_approximation = FastApproximation;
319 static constexpr double vfp_scale() noexcept {
return static_cast<double>(uint64_t{1} << fractional_bits); }
325 if (scaled >=
static_cast<double>(std::numeric_limits<BaseType>::max()) + 1.0) {
326 return std::numeric_limits<BaseType>::max();
328 if (scaled <=
static_cast<double>(std::numeric_limits<BaseType>::min()) - 1.0) {
329 return std::numeric_limits<BaseType>::min();
331 return static_cast<BaseType
>(scaled);
336 if (value != value) {
344 return static_cast<float>(
static_cast<double>(
raw) / vfp_scale());
348 static constexpr double raw_to_double(BaseType
raw)
noexcept {
return static_cast<double>(
raw) / vfp_scale(); }
355 template <std::
size_t OtherFractionalBits>
357 if constexpr (FractionalBits == OtherFractionalBits) {
360 else if constexpr (FractionalBits > OtherFractionalBits) {
362 constexpr int32_t shift = FractionalBits - OtherFractionalBits;
363 value_ = signed_saturate<32 - shift>(value_);
364 value_ = (value_ << shift) + (value_ % 2);
366 else if constexpr (rounded) {
368 constexpr int32_t shift = OtherFractionalBits - FractionalBits;
369 value_ >>= shift + ((1 << shift) - 1);
373 value_ >>= (OtherFractionalBits - FractionalBits);
379 template <std::
integral T>
380 constexpr explicit FixedPoint(T value) noexcept : value_(
static_cast<BaseType
>(value) << fractional_bits) {}
389 if (!std::is_constant_evaluated()) {
390 asm(
"vcvt.s32.f32 %0, %0, %1" :
"+t"(value) :
"I"(fractional_bits));
391 value_ = std::bit_cast<int32_t>(value);
400 constexpr explicit operator float() const noexcept {
402 if (!std::is_constant_evaluated()) {
403 int32_t output = value_;
404 asm(
"vcvt.f32.s32 %0, %0, %1" :
"+t"(output) :
"I"(fractional_bits));
405 return std::bit_cast<float>(output);
415 if (!std::is_constant_evaluated()) {
416 auto output = std::bit_cast<int64_t>(value);
420 asm(
"vcvt.s32.f64 %P0, %P0, %1" :
"+w"(output) :
"I"(fractional_bits));
421 value_ =
static_cast<BaseType
>(output);
430 explicit operator double() const noexcept {
432 if (!std::is_constant_evaluated()) {
433 auto output = std::bit_cast<double>((int64_t)value_);
434 asm(
"vcvt.f64.s32 %P0, %P0, %1" :
"+w"(output) :
"I"(fractional_bits));
442 template <std::
size_t OutputFractionalBits>
448 template <std::
integral T>
449 explicit operator T() const noexcept {
450 return static_cast<T
>(value_ >> fractional_bits);
453 explicit operator bool() const noexcept {
return value_ != 0; }
459 [[nodiscard]]
constexpr BaseType
raw() const noexcept {
return value_; }
475 value_ = add_saturate(value_, rhs.value_);
482 return from_raw(subtract_saturate(value_, rhs.value_));
488 value_ = subtract_saturate(value_, rhs.value_);
495 if constexpr (fast_approximation && fractional_bits > 16) {
497 constexpr int32_t shift = fractional_bits - ((fractional_bits * 2) - 32);
498 return from_raw(signed_most_significant_word_multiply(value_, rhs.value_) << shift);
501 if constexpr (rounded) {
502 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.value_) >> (fractional_bits - 1);
503 return from_raw(
static_cast<BaseType
>((value >> 1) + (value % 2)));
506 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.value_) >> fractional_bits;
507 return from_raw(
static_cast<BaseType
>(value));
519 template <std::size_t OutputFractionalBits = FractionalBits, std::size_t OtherFractionalBits,
bool OtherRounded,
520 bool OtherApproximating>
521 requires(OtherRounded == Rounded && OtherApproximating == FastApproximation)
524 if constexpr (fast_approximation) {
525 constexpr int32_t l_shift = OutputFractionalBits - ((FractionalBits + OtherFractionalBits) - 32);
526 static_assert(l_shift < 32 && l_shift > -32);
527 BaseType value = signed_most_significant_word_multiply(value_, rhs.
raw());
528 return from_raw(l_shift > 0 ? value << l_shift : value >> -l_shift);
531 constexpr int32_t r_shift = (FractionalBits + OtherFractionalBits) - OutputFractionalBits;
532 if constexpr (rounded) {
533 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.
raw())
535 return from_raw(
static_cast<BaseType
>((value / 2) + (value % 2)));
538 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.
raw()) >> r_shift;
539 return from_raw(
static_cast<BaseType
>(value));
544 template <std::
size_t OtherFractionalBits>
553 if (rhs.value_ == 0) {
554 return from_raw(std::numeric_limits<BaseType>::max());
556 if constexpr (rounded) {
557 IntermediateType value = (
static_cast<IntermediateType
>(value_) << (fractional_bits + 1)) / rhs.value_;
558 return from_raw(
static_cast<BaseType
>((value / 2) + (value % 2)));
561 IntermediateType value = (
static_cast<IntermediateType
>(value_) << fractional_bits) / rhs.value_;
562 return from_raw(
static_cast<BaseType
>(value));
573 template <std::
size_t OtherFractionalBitsA, std::
size_t OtherFractionalBitsB>
578 if constexpr (fast_approximation && (OtherFractionalBitsA + OtherFractionalBitsB) - 32 == FractionalBits) {
581 return *
this +
static_cast<FixedPoint>(a * b);
586 if constexpr (fast_approximation && (((FractionalBits * 2) - 32) == (FractionalBits - 1))) {
587 return from_raw(
static_cast<FixedPoint<FractionalBits - 1
>>(*this).MultiplyAdd(a, b).raw() << 1);
589 return *
this + (a * b);
599 template <std::
size_t OtherFractionalBits>
601 int integral_value = value_ >> fractional_bits;
602 int other_integral_value = rhs.
raw() >> OtherFractionalBits;
603 int fractional_value = value_ & ((1 << fractional_bits) - 1);
604 int other_fractional_value = rhs.
raw() & ((1 << OtherFractionalBits) - 1);
607 if (fractional_bits > OtherFractionalBits) {
608 fractional_value >>= fractional_bits - OtherFractionalBits;
611 other_fractional_value >>= OtherFractionalBits - fractional_bits;
614 return integral_value == other_integral_value && fractional_value == other_fractional_value;
618 template <std::
size_t OtherFractionalBits>
621 int integral_value = value_ >> fractional_bits;
622 int other_integral_value = rhs.
raw() >> OtherFractionalBits;
623 int fractional_value = value_ & ((1 << fractional_bits) - 1);
624 int other_fractional_value = rhs.
raw() & ((1 << OtherFractionalBits) - 1);
627 if (fractional_bits > OtherFractionalBits) {
628 fractional_value >>= fractional_bits - OtherFractionalBits;
631 other_fractional_value >>= OtherFractionalBits - fractional_bits;
634 if (integral_value < other_integral_value) {
635 return std::strong_ordering::less;
637 if (integral_value > other_integral_value) {
638 return std::strong_ordering::greater;
640 if (fractional_value < other_fractional_value) {
641 return std::strong_ordering::less;
643 if (fractional_value > other_fractional_value) {
644 return std::strong_ordering::greater;
646 return std::strong_ordering::equal;
650 template <
typename T>
651 requires std::integral<T> || std::floating_point<T>
Fixed point number with a configurable number of fractional bits.
Definition fixedpoint.h:266
constexpr bool operator==(const FixedPoint &rhs) const noexcept
Equality operator.
Definition fixedpoint.h:593
constexpr FixedPoint operator*=(const FixedPoint< OtherFractionalBits > &rhs)
Multiplication operator Multiply two fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:545
constexpr FixedPoint(float value) noexcept
Convert from a float to a fixed point number.
Definition fixedpoint.h:384
constexpr std::strong_ordering operator<=>(const FixedPoint &rhs) const noexcept
Three-way comparison operator.
Definition fixedpoint.h:596
static constexpr BaseType saturate_to_raw(double scaled) noexcept
Round toward zero and saturate a scaled real value to int32, as VFP's f->fixed convert does.
Definition fixedpoint.h:322
static constexpr float raw_to_float(BaseType raw) noexcept
vcvt.f32.s32: fixed point -> float (a single round-to-nearest, as the hardware does).
Definition fixedpoint.h:343
constexpr FixedPoint operator/(const FixedPoint &rhs) const
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:552
constexpr FixedPoint(T value) noexcept
Convert an integer to a fixed point number.
Definition fixedpoint.h:380
constexpr FixedPoint< OutputFractionalBits > as() const
Convert to a fixed point number with a different number of fractional bits.
Definition fixedpoint.h:443
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:574
constexpr FixedPoint operator/=(const FixedPoint &rhs)
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:567
static int32_t signed_most_significant_word_multiply_add(int32_t a, int32_t b, int32_t c)
a + b * c
Definition fixedpoint.h:274
constexpr bool operator==(const FixedPoint< OtherFractionalBits > &rhs) const noexcept
Equality operator for fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:600
constexpr FixedPoint(FixedPoint< OtherFractionalBits > other) noexcept
Construct a fixed point number from another fixed point number.
Definition fixedpoint.h:356
constexpr FixedPoint operator+(const FixedPoint &rhs) const
Addition operator Add two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:470
static constexpr BaseType float_to_raw(double value) noexcept
vcvt.s32.f32 / vcvt.s32.f64: floating point -> fixed point. (float promotes to double exactly....
Definition fixedpoint.h:335
constexpr FixedPoint operator-() const
Negation operator.
Definition fixedpoint.h:456
constexpr FixedPoint operator*(const FixedPoint &rhs) const
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:494
constexpr BaseType raw() const noexcept
Get the internal value.
Definition fixedpoint.h:459
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:619
static constexpr FixedPoint from_raw(BaseType raw) noexcept
Construct from a raw value.
Definition fixedpoint.h:462
constexpr FixedPoint operator-(const FixedPoint &rhs) const
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:481
constexpr FixedPoint operator*=(const FixedPoint &rhs)
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:512
constexpr FixedPoint(double value) noexcept
Convert from a double to a fixed point number.
Definition fixedpoint.h:413
constexpr FixedPoint operator+=(const FixedPoint &rhs)
Addition operator Add two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:474
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:585
constexpr bool operator==(const T &rhs) const noexcept
Equality operator for integers and floating point numbers.
Definition fixedpoint.h:652
constexpr FixedPoint operator-=(const FixedPoint &rhs)
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:487
static constexpr double raw_to_double(BaseType raw) noexcept
vcvt.f64.s32: fixed point -> double (exact).
Definition fixedpoint.h:348
constexpr FixedPoint()=default
Default constructor.