19#include "intrinsics.h"
30template <
size_t bit,
typename T>
31requires(bit > 0 && bit < 32)
32[[gnu::always_inline]] [[nodiscard]]
constexpr T roundToBit(T value) {
33 return value + (T{1} << bit) - T{1};
37[[gnu::always_inline]]
static inline int32_t toPositive(int32_t a) {
38 return ((a / 2) + (1073741824));
46template <std::
size_t FractionalBits,
bool Rounded = false,
bool FastApproximation = (FractionalBits == 31 && ARMv7a)>
48 static_assert(FractionalBits > 0,
"FractionalBits must be greater than 0");
49 static_assert(FractionalBits < 32,
"FractionalBits must be less than 32");
51 using BaseType = int32_t;
52 using IntermediateType = int64_t;
56 if constexpr (Rounded) {
57 return multiply_accumulate_32x32_rshift32_rounded(a, b, c);
60 return multiply_accumulate_32x32_rshift32(a, b, c);
65 [[gnu::always_inline]]
static int32_t signed_most_significant_word_multiply(int32_t a, int32_t b) {
66 if constexpr (Rounded) {
67 return multiply_32x32_rshift32_rounded(a, b);
70 return multiply_32x32_rshift32(a, b);
75 static consteval uint32_t one() noexcept {
76 return 1 << FractionalBits;
79 constexpr static std::size_t fractional_bits = FractionalBits;
80 constexpr static std::size_t integral_bits = 32 - FractionalBits;
81 constexpr static bool rounded = Rounded;
82 constexpr static bool fast_approximation = FastApproximation;
92 template <std::
size_t OtherFractionalBits>
94 : value_(other.raw()) {
95 if constexpr (FractionalBits == OtherFractionalBits) {
98 else if constexpr (FractionalBits > OtherFractionalBits) {
100 constexpr int32_t shift = FractionalBits - OtherFractionalBits;
101 value_ = signed_saturate<32 - shift>(value_);
102 value_ = (value_ << shift) + (value_ % 2);
104 else if constexpr (rounded) {
106 constexpr int32_t shift = OtherFractionalBits - FractionalBits;
107 value_ = roundToBit<shift>(value_) >> shift;
111 value_ >>= (OtherFractionalBits - FractionalBits);
115 template <std::
size_t OtherFractionalBits>
122 template <std::
integral T>
123 constexpr explicit FixedPoint(T value) noexcept : value_(
static_cast<BaseType
>(value) << fractional_bits) {}
128#if __ARM_ARCH_7A__ && !defined(__clang__)
130 asm(
"vcvt.s32.f32 %0, %1, %2" :
"=t"(value) :
"t"(value),
"I"(fractional_bits));
134 value *=
static_cast<double>(FixedPoint::one());
136 if constexpr (rounded) {
137 value = std::round(value);
142 static_cast<int64_t
>(value), std::numeric_limits<BaseType>::min(), std::numeric_limits<BaseType>::max())));
147 template <std::
size_t OtherFractionalBits,
bool OtherRounded = Rounded,
bool OtherApproximating = FastApproximation>
154 [[gnu::always_inline]]
explicit constexpr operator float() const noexcept {
return to_float(); }
158 [[gnu::always_inline]] [[nodiscard]]
constexpr float to_float() const noexcept {
159#if __ARM_ARCH_7A__ && !defined(__clang__)
161 int32_t output = value_;
162 asm(
"vcvt.f32.s32 %0, %1, %2" :
"=t"(output) :
"t"(output),
"I"(fractional_bits));
163 return std::bit_cast<float>(output);
167 return static_cast<float>(value_) / FixedPoint::one();
173#if __ARM_ARCH_7A__ && !defined(__clang__)
175 auto output = std::bit_cast<int64_t>(value);
176 asm(
"vcvt.s32.f64 %0, %1, %2" :
"=w"(output) :
"w"(output),
"I"(fractional_bits));
180 value *=
static_cast<double>(FixedPoint::one());
182 if constexpr (rounded) {
183 value = std::round(value);
188 static_cast<int64_t
>(value), std::numeric_limits<BaseType>::min(), std::numeric_limits<BaseType>::max())));
195 [[gnu::always_inline]]
explicit constexpr operator double() const noexcept {
196#if __ARM_ARCH_7A__ && !defined(__clang__)
198 auto output = std::bit_cast<double>((int64_t)value_);
199 asm(
"vcvt.f64.s32 %0, %1, %2" :
"=w"(output) :
"w"(output),
"I"(fractional_bits));
204 return static_cast<double>(value_) / FixedPoint::one();
208 template <std::
size_t OutputFractionalBits>
214 template <std::
signed_
integral T>
215 constexpr explicit operator T() const noexcept {
216 if constexpr (rounded) {
218 return static_cast<T
>(roundToBit<fractional_bits>(value_) >> fractional_bits);
226 constexpr explicit operator bool() const noexcept {
return value_ != 0; }
232 [[gnu::always_inline]] [[nodiscard]]
constexpr BaseType
raw() const noexcept {
return value_; }
233 [[gnu::always_inline]]
constexpr BaseType&
raw() noexcept {
return value_; }
245 return from_raw(add_saturate(value_, rhs.value_));
251 value_ = add_saturate(value_, rhs.value_);
258 return from_raw(subtract_saturate(value_, rhs.value_));
264 value_ = subtract_saturate(value_, rhs.value_);
271 if constexpr (fast_approximation && fractional_bits > 16) {
273 constexpr int32_t shift = fractional_bits - ((fractional_bits * 2) - 32);
274 return from_raw(signed_most_significant_word_multiply(value_, rhs.value_) << shift);
276 else if constexpr (rounded) {
277 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.value_) >> (fractional_bits - 1);
278 return from_raw(
static_cast<BaseType
>((value >> 1) + (value % 2)));
281 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.value_) >> fractional_bits;
282 return from_raw(
static_cast<BaseType
>(value));
295 template <std::size_t OutputFractionalBits = FractionalBits, std::size_t OtherFractionalBits,
bool OtherRounded,
296 bool OtherApproximating>
297 requires(OtherRounded == Rounded && OtherApproximating == FastApproximation)
300 if constexpr (fast_approximation) {
301 constexpr int32_t l_shift = OutputFractionalBits - ((FractionalBits + OtherFractionalBits) - 32);
302 static_assert(l_shift < 32 && l_shift > -32);
303 BaseType value = signed_most_significant_word_multiply(value_, rhs.
raw());
304 return from_raw(l_shift > 0 ? value << l_shift : value >> -l_shift);
307 constexpr int32_t r_shift = (FractionalBits + OtherFractionalBits) - OutputFractionalBits;
308 if constexpr (rounded) {
309 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.
raw())
311 return from_raw(
static_cast<BaseType
>((value / 2) + (value % 2)));
314 IntermediateType value = (
static_cast<IntermediateType
>(value_) * rhs.
raw()) >> r_shift;
315 return from_raw(
static_cast<BaseType
>(value));
320 template <std::
size_t OtherFractionalBits>
329 if constexpr (rounded) {
330 IntermediateType value = (
static_cast<IntermediateType
>(value_) << (fractional_bits + 1)) / rhs.value_;
331 return from_raw(
static_cast<BaseType
>((value / 2) + (value % 2)));
334 IntermediateType value = (
static_cast<IntermediateType
>(value_) << fractional_bits) / rhs.value_;
335 return from_raw(
static_cast<BaseType
>(value));
341 template <std::size_t OtherFractionalBits,
342 std::size_t ResultFractionalBits = std::max(FractionalBits, OtherFractionalBits)
343 - std::min(FractionalBits, OtherFractionalBits)>
345 requires(ResultFractionalBits < std::max(FractionalBits, OtherFractionalBits))
346 && (ResultFractionalBits > std::min(FractionalBits, OtherFractionalBits))
349 if (rhs.
raw() == 0) {
353 constexpr int shift =
static_cast<int32_t
>(FractionalBits) - OtherFractionalBits;
354 IntermediateType result{};
355 if constexpr (shift > 0) {
357 result = (
static_cast<IntermediateType
>(value_) << shift) / rhs.
raw();
359 else if constexpr (shift < 0) {
361 result = (
static_cast<IntermediateType
>(value_) / (rhs.
raw() << -shift));
365 result =
static_cast<IntermediateType
>(value_) / rhs.
raw();
367 size_t result_shift = std::max(FractionalBits, OtherFractionalBits) - ResultFractionalBits;
369 if constexpr (rounded) {
371 result += (1 << (result_shift - 1));
386 template <std::
size_t OtherFractionalBitsA, std::
size_t OtherFractionalBitsB>
391 if constexpr (fast_approximation && (OtherFractionalBitsA + OtherFractionalBitsB) - 32 == FractionalBits) {
395 return *
this +
static_cast<FixedPoint>(a * b);
402 if constexpr (fast_approximation && (((fractional_bits * 2) - 32) == (fractional_bits - 1))) {
407 return *
this + (a * b);
413 return value_ == rhs.value_;
420 template <std::
size_t OtherFractionalBits>
422 int integral_value = value_ >> fractional_bits;
423 int other_integral_value = rhs.
raw() >> OtherFractionalBits;
424 int fractional_value = value_ & ((1 << fractional_bits) - 1);
425 int other_fractional_value = rhs.
raw() & ((1 << OtherFractionalBits) - 1);
428 if constexpr (fractional_bits > OtherFractionalBits) {
429 fractional_value >>= fractional_bits - OtherFractionalBits;
432 other_fractional_value >>= OtherFractionalBits - fractional_bits;
435 return integral_value == other_integral_value && fractional_value == other_fractional_value;
439 template <std::
size_t OtherFractionalBits>
442 int integral_value = value_ >> fractional_bits;
443 int other_integral_value = rhs.
raw() >> OtherFractionalBits;
444 int fractional_value = value_ & ((1 << fractional_bits) - 1);
445 int other_fractional_value = rhs.
raw() & ((1 << OtherFractionalBits) - 1);
448 if (fractional_bits > OtherFractionalBits) {
449 fractional_value >>= fractional_bits - OtherFractionalBits;
452 other_fractional_value >>= OtherFractionalBits - fractional_bits;
455 if (integral_value < other_integral_value) {
456 return std::strong_ordering::less;
458 if (integral_value > other_integral_value) {
459 return std::strong_ordering::greater;
461 if (fractional_value < other_fractional_value) {
462 return std::strong_ordering::less;
464 if (fractional_value > other_fractional_value) {
465 return std::strong_ordering::greater;
467 return std::strong_ordering::equal;
480 [[gnu::always_inline]]
constexpr FixedPoint operator*(
const std::integral
auto& rhs)
const {
486 [[gnu::always_inline]] [[nodiscard]]
constexpr int32_t integral()
const {
487 return static_cast<int32_t
>(value_ >> fractional_bits);
490 [[gnu::always_inline]]
constexpr FixedPoint absolute() const noexcept {
491 if constexpr (fractional_bits == 31) {
493 return from_raw((value_ / 2) + (1073741824));
496 return from_raw(value_ < 0 ? -value_ : value_);
505template <std::
integral T, std::
size_t FractionalBits,
bool Rounded,
bool FastApproximation>
511template <std::
floating_po
int T, std::
size_t FractionalBits,
bool Rounded,
bool FastApproximation>
517template <std::
floating_po
int T, std::
size_t FractionalBits,
bool Rounded,
bool FastApproximation>
523template <std::
floating_po
int T, std::
size_t FractionalBits,
bool Rounded,
bool FastApproximation>
531constexpr int32_t ONE_Q31 = std::numeric_limits<int32_t>::max();
532constexpr float ONE_Q31f =
static_cast<float>(ONE_Q31);
533constexpr int32_t ONE_Q16 = std::numeric_limits<uint16_t>::max();
534constexpr int32_t NEGATIVE_ONE_Q31 = std::numeric_limits<int32_t>::min();
535constexpr int32_t ONE_OVER_SQRT2_Q31 = ONE_Q31 / std::numbers::sqrt2;
538constexpr float ONE_Q31f =
static_cast<float>(ONE_Q31);
541constexpr int32_t ONE_OVER_SQRT2_Q31 =
FixedPoint<31>{1 / std::numbers::sqrt2}.
raw();
544static_assert(ONE_Q31 == std::numeric_limits<int32_t>::max());
545static_assert(ONE_Q31f == 1.0f * std::numeric_limits<int32_t>::max());
546static_assert(ONE_Q16 == std::numeric_limits<uint16_t>::max());
547static_assert(NEGATIVE_ONE_Q31 == std::numeric_limits<int32_t>::min());
548static_assert(ONE_OVER_SQRT2_Q31 == 1518500249);
Fixed point number with a configurable number of fractional bits.
Definition fixedpoint.h:47
constexpr FixedPoint DivideInt(const std::integral auto &rhs) const
Divide by an integral type.
Definition fixedpoint.h:476
constexpr bool operator==(const FixedPoint &rhs) const noexcept
Equality operator.
Definition fixedpoint.h:412
constexpr FixedPoint operator*=(const FixedPoint< OtherFractionalBits > &rhs)
Multiplication operator Multiply two fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:321
constexpr std::strong_ordering operator<=>(const FixedPoint &rhs) const noexcept
Three-way comparison operator.
Definition fixedpoint.h:417
constexpr FixedPoint operator/(const FixedPoint &rhs) const
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:328
constexpr float to_float() const noexcept
Explicit conversion to float.
Definition fixedpoint.h:158
constexpr FixedPoint(T value) noexcept
Convert an integer to a fixed point number.
Definition fixedpoint.h:123
static constexpr FixedPoint from_float(float value) noexcept
Convert from a float to a fixed point number.
Definition fixedpoint.h:127
constexpr FixedPoint< OutputFractionalBits > as() const
Convert to a fixed point number with a different number of fractional bits.
Definition fixedpoint.h:209
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:387
constexpr FixedPoint operator/=(const FixedPoint &rhs)
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:379
static int32_t signed_most_significant_word_multiply_add(int32_t a, int32_t b, int32_t c)
a + b * c
Definition fixedpoint.h:55
constexpr FixedPoint< ResultFractionalBits, Rounded, FastApproximation > operator/(const FixedPoint< OtherFractionalBits > &rhs) const
Division operator Divide two fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:348
constexpr bool operator==(const FixedPoint< OtherFractionalBits > &rhs) const noexcept
Equality operator for fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:421
static constexpr FixedPoint from_float(double value) noexcept
Convert from a double to a fixed point number.
Definition fixedpoint.h:172
constexpr FixedPoint(FixedPoint< OtherFractionalBits > other) noexcept
Construct a fixed point number from another fixed point number.
Definition fixedpoint.h:93
constexpr FixedPoint operator+(const FixedPoint &rhs) const
Addition operator Add two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:244
constexpr FixedPoint operator-() const
Negation operator.
Definition fixedpoint.h:229
constexpr FixedPoint operator*(const FixedPoint &rhs) const
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:270
constexpr BaseType raw() const noexcept
Get the internal value.
Definition fixedpoint.h:232
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:440
static constexpr FixedPoint from_raw(BaseType raw) noexcept
Construct from a raw value.
Definition fixedpoint.h:236
constexpr FixedPoint operator-(const FixedPoint &rhs) const
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:257
constexpr FixedPoint operator*=(const FixedPoint &rhs)
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:288
constexpr FixedPoint operator+=(const FixedPoint &rhs)
Addition operator Add two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:250
constexpr FixedPoint MultiplyInt(const std::integral auto &rhs) const
Multiply by an integral type.
Definition fixedpoint.h:471
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:401
constexpr FixedPoint operator-=(const FixedPoint &rhs)
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:263
constexpr FixedPoint()=default
Default constructor.