Deluge Firmware 1.3.0
Build date: 2025.06.05
Loading...
Searching...
No Matches
fixedpoint.h
1/*
2 * Copyright © 2014-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#include "intrinsics.h"
20#include <bit>
21#include <cmath>
22#include <compare>
23#include <concepts>
24#include <limits>
25#include <numbers>
26
27using q31_t = int32_t;
28using q63_t = int64_t;
29
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};
34}
35
36// This converts the range -2^31 to 2^31 to the range 0-2^31
37[[gnu::always_inline]] static inline int32_t toPositive(int32_t a) {
38 return ((a / 2) + (1073741824));
39}
40
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");
50
51 using BaseType = int32_t;
52 using IntermediateType = int64_t;
53
55 [[gnu::always_inline]] static int32_t signed_most_significant_word_multiply_add(int32_t a, int32_t b, int32_t c) {
56 if constexpr (Rounded) {
57 return multiply_accumulate_32x32_rshift32_rounded(a, b, c);
58 }
59 else {
60 return multiply_accumulate_32x32_rshift32(a, b, c);
61 }
62 }
63
64 // a * b
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);
68 }
69 else {
70 return multiply_32x32_rshift32(a, b);
71 }
72 }
73
74public:
75 static consteval uint32_t one() noexcept {
76 return 1 << FractionalBits; // 1.0 in fixed point representation
77 }
78
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;
83
84 constexpr static FixedPoint max() noexcept { return FixedPoint::from_raw(std::numeric_limits<BaseType>::max()); }
85 constexpr static FixedPoint min() noexcept { return FixedPoint::from_raw(std::numeric_limits<BaseType>::min()); }
86
88 constexpr FixedPoint() = default;
89
92 template <std::size_t OtherFractionalBits>
93 [[gnu::always_inline]] constexpr explicit FixedPoint(FixedPoint<OtherFractionalBits> other) noexcept
94 : value_(other.raw()) {
95 if constexpr (FractionalBits == OtherFractionalBits) {
96 return;
97 }
98 else if constexpr (FractionalBits > OtherFractionalBits) {
99 // saturate (shift left)
100 constexpr int32_t shift = FractionalBits - OtherFractionalBits;
101 value_ = signed_saturate<32 - shift>(value_);
102 value_ = (value_ << shift) + (value_ % 2);
103 }
104 else if constexpr (rounded) {
105 // round (shift right)
106 constexpr int32_t shift = OtherFractionalBits - FractionalBits;
107 value_ = roundToBit<shift>(value_) >> shift;
108 }
109 else {
110 // truncate (shift right)
111 value_ >>= (OtherFractionalBits - FractionalBits);
112 }
113 }
114
115 template <std::size_t OtherFractionalBits>
116 constexpr operator FixedPoint<OtherFractionalBits>() const {
118 }
119
122 template <std::integral T>
123 constexpr explicit FixedPoint(T value) noexcept : value_(static_cast<BaseType>(value) << fractional_bits) {}
124
127 [[gnu::always_inline]] static constexpr FixedPoint from_float(float value) noexcept {
128#if __ARM_ARCH_7A__ && !defined(__clang__)
129 if !consteval {
130 asm("vcvt.s32.f32 %0, %1, %2" : "=t"(value) : "t"(value), "I"(fractional_bits));
131 return FixedPoint::from_raw(std::bit_cast<int32_t>(value)); // NOLINT
132 }
133#endif
134 value *= static_cast<double>(FixedPoint::one());
135 // convert from floating-point to fixed point
136 if constexpr (rounded) {
137 value = std::round(value);
138 }
139
140 // saturate
141 return FixedPoint::from_raw(static_cast<BaseType>(std::clamp<int64_t>(
142 static_cast<int64_t>(value), std::numeric_limits<BaseType>::min(), std::numeric_limits<BaseType>::max())));
143 }
144
145 consteval FixedPoint(float value) noexcept : value_(from_float(value).raw()) {}
146
147 template <std::size_t OtherFractionalBits, bool OtherRounded = Rounded, bool OtherApproximating = FastApproximation>
150 }
151
154 [[gnu::always_inline]] explicit constexpr operator float() const noexcept { return to_float(); }
155
158 [[gnu::always_inline]] [[nodiscard]] constexpr float to_float() const noexcept {
159#if __ARM_ARCH_7A__ && !defined(__clang__)
160 if !consteval {
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);
164 }
165#endif
166
167 return static_cast<float>(value_) / FixedPoint::one();
168 }
169
172 [[gnu::always_inline]] static constexpr FixedPoint from_float(double value) noexcept {
173#if __ARM_ARCH_7A__ && !defined(__clang__)
174 if !consteval {
175 auto output = std::bit_cast<int64_t>(value);
176 asm("vcvt.s32.f64 %0, %1, %2" : "=w"(output) : "w"(output), "I"(fractional_bits));
177 return FixedPoint::from_raw(static_cast<BaseType>(output));
178 }
179#endif
180 value *= static_cast<double>(FixedPoint::one());
181 // convert from floating-point to fixed point
182 if constexpr (rounded) {
183 value = std::round(value);
184 }
185
186 // saturate
187 return FixedPoint::from_raw(static_cast<BaseType>(std::clamp<int64_t>(
188 static_cast<int64_t>(value), std::numeric_limits<BaseType>::min(), std::numeric_limits<BaseType>::max())));
189 }
190
191 consteval FixedPoint(double value) noexcept : value_(from_float(value).raw()) {}
192
195 [[gnu::always_inline]] explicit constexpr operator double() const noexcept {
196#if __ARM_ARCH_7A__ && !defined(__clang__)
197 if !consteval {
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));
200 return output;
201 }
202#endif
203
204 return static_cast<double>(value_) / FixedPoint::one();
205 }
206
208 template <std::size_t OutputFractionalBits>
209 [[gnu::always_inline]] constexpr FixedPoint<OutputFractionalBits> as() const {
210 return static_cast<FixedPoint<OutputFractionalBits>>(*this);
211 }
212
214 template <std::signed_integral T>
215 constexpr explicit operator T() const noexcept {
216 if constexpr (rounded) {
217 // round to nearest integer
218 return static_cast<T>(roundToBit<fractional_bits>(value_) >> fractional_bits);
219 }
220 else {
221 // return the integral
222 return integral();
223 }
224 }
225
226 constexpr explicit operator bool() const noexcept { return value_ != 0; }
227
229 [[gnu::always_inline]] [[nodiscard]] constexpr FixedPoint operator-() const { return from_raw(-value_); }
230
232 [[gnu::always_inline]] [[nodiscard]] constexpr BaseType raw() const noexcept { return value_; }
233 [[gnu::always_inline]] constexpr BaseType& raw() noexcept { return value_; }
234
236 [[gnu::always_inline]] static constexpr FixedPoint from_raw(BaseType raw) noexcept {
237 FixedPoint result{};
238 result.value_ = raw;
239 return result;
240 }
241
244 [[gnu::always_inline]] constexpr FixedPoint operator+(const FixedPoint& rhs) const {
245 return from_raw(add_saturate(value_, rhs.value_));
246 }
247
250 [[gnu::always_inline]] constexpr FixedPoint operator+=(const FixedPoint& rhs) {
251 value_ = add_saturate(value_, rhs.value_);
252 return *this;
253 }
254
257 [[gnu::always_inline]] constexpr FixedPoint operator-(const FixedPoint& rhs) const {
258 return from_raw(subtract_saturate(value_, rhs.value_));
259 }
260
263 [[gnu::always_inline]] constexpr FixedPoint operator-=(const FixedPoint& rhs) {
264 value_ = subtract_saturate(value_, rhs.value_);
265 return *this;
266 }
267
270 [[gnu::always_inline]] constexpr FixedPoint operator*(const FixedPoint& rhs) const {
271 if constexpr (fast_approximation && fractional_bits > 16) {
272 // less than 16 would mean no fractional bits remain after right shift by 32
273 constexpr int32_t shift = fractional_bits - ((fractional_bits * 2) - 32);
274 return from_raw(signed_most_significant_word_multiply(value_, rhs.value_) << shift);
275 }
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)));
279 }
280 else {
281 IntermediateType value = (static_cast<IntermediateType>(value_) * rhs.value_) >> fractional_bits;
282 return from_raw(static_cast<BaseType>(value));
283 }
284 }
285
288 [[gnu::always_inline]] constexpr FixedPoint operator*=(const FixedPoint& rhs) {
289 value_ = this->operator*(rhs).value_;
290 return *this;
291 }
292
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);
305 }
306
307 constexpr int32_t r_shift = (FractionalBits + OtherFractionalBits) - OutputFractionalBits;
308 if constexpr (rounded) {
309 IntermediateType value = (static_cast<IntermediateType>(value_) * rhs.raw())
310 >> (r_shift - 1); // At this point Q is FractionalBits + OtherFractionalBits
311 return from_raw(static_cast<BaseType>((value / 2) + (value % 2)));
312 }
313
314 IntermediateType value = (static_cast<IntermediateType>(value_) * rhs.raw()) >> r_shift;
315 return from_raw(static_cast<BaseType>(value));
316 }
317
320 template <std::size_t OtherFractionalBits>
321 [[gnu::always_inline]] constexpr FixedPoint operator*=(const FixedPoint<OtherFractionalBits>& rhs) {
322 value_ = this->operator*(rhs).value_;
323 return *this;
324 }
325
328 [[gnu::always_inline]] constexpr FixedPoint operator/(const FixedPoint& rhs) const {
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)));
332 }
333 else {
334 IntermediateType value = (static_cast<IntermediateType>(value_) << fractional_bits) / rhs.value_;
335 return from_raw(static_cast<BaseType>(value));
336 }
337 }
338
341 template <std::size_t OtherFractionalBits,
342 std::size_t ResultFractionalBits = std::max(FractionalBits, OtherFractionalBits)
343 - std::min(FractionalBits, OtherFractionalBits)>
344
345 requires(ResultFractionalBits < std::max(FractionalBits, OtherFractionalBits))
346 && (ResultFractionalBits > std::min(FractionalBits, OtherFractionalBits))
349 if (rhs.raw() == 0) {
350 return FixedPoint<ResultFractionalBits>::from_raw(std::numeric_limits<BaseType>::max());
351 }
352
353 constexpr int shift = static_cast<int32_t>(FractionalBits) - OtherFractionalBits;
354 IntermediateType result{};
355 if constexpr (shift > 0) {
356 // this means we have more fractional bits than the divisor
357 result = (static_cast<IntermediateType>(value_) << shift) / rhs.raw();
358 }
359 else if constexpr (shift < 0) {
360 // this means we have less fractional bits than the divisor
361 result = (static_cast<IntermediateType>(value_) / (rhs.raw() << -shift));
362 }
363 else {
364 // same number of fractional bits
365 result = static_cast<IntermediateType>(value_) / rhs.raw();
366 }
367 size_t result_shift = std::max(FractionalBits, OtherFractionalBits) - ResultFractionalBits;
368
369 if constexpr (rounded) {
370 // round the result
371 result += (1 << (result_shift - 1)); // add half to round
372 }
373 // shift to get the correct number of fractional bits
375 }
376
379 [[gnu::always_inline]] constexpr FixedPoint operator/=(const FixedPoint& rhs) {
380 value_ = this->operator/(rhs).value_;
381 return *this;
382 }
383
386 template <std::size_t OtherFractionalBitsA, std::size_t OtherFractionalBitsB>
388 const FixedPoint<OtherFractionalBitsB>& b) const {
389 // ensure that the number of fractional bits in the addend is equal to the sum of the number of fractional bits
390 // in multiplicands, minus 32 (due to right shift) before using smmla/smmlar
391 if constexpr (fast_approximation && (OtherFractionalBitsA + OtherFractionalBitsB) - 32 == FractionalBits) {
393 }
394 else {
395 return *this + static_cast<FixedPoint>(a * b);
396 }
397 }
398
401 [[nodiscard]] constexpr FixedPoint MultiplyAdd(const FixedPoint& a, const FixedPoint& b) const {
402 if constexpr (fast_approximation && (((fractional_bits * 2) - 32) == (fractional_bits - 1))) {
403 // fractional_bits - 1 is due to the left shift
404 return from_raw(signed_most_significant_word_multiply_add(value_ >> 1, a.raw(), b.raw()) << 1);
405 }
406 else {
407 return *this + (a * b);
408 }
409 }
410
412 [[gnu::always_inline]] constexpr bool operator==(const FixedPoint& rhs) const noexcept {
413 return value_ == rhs.value_;
414 }
415
417 constexpr std::strong_ordering operator<=>(const FixedPoint& rhs) const noexcept { return value_ <=> rhs.value_; }
418
420 template <std::size_t OtherFractionalBits>
421 constexpr bool operator==(const FixedPoint<OtherFractionalBits>& rhs) const noexcept {
422 int integral_value = value_ >> fractional_bits;
423 int other_integral_value = rhs.raw() >> OtherFractionalBits;
424 int fractional_value = value_ & ((1 << fractional_bits) - 1); // Mask out the integral part
425 int other_fractional_value = rhs.raw() & ((1 << OtherFractionalBits) - 1); // Mask out the integral parts
426
427 // Shift the fractional part if the number of fractional bits is different
428 if constexpr (fractional_bits > OtherFractionalBits) {
429 fractional_value >>= fractional_bits - OtherFractionalBits;
430 }
431 else {
432 other_fractional_value >>= OtherFractionalBits - fractional_bits;
433 }
434
435 return integral_value == other_integral_value && fractional_value == other_fractional_value;
436 }
437
439 template <std::size_t OtherFractionalBits>
440 constexpr std::strong_ordering operator<=>(const FixedPoint<OtherFractionalBits>& rhs) const noexcept {
441 // Compare integral and fractional components separately
442 int integral_value = value_ >> fractional_bits;
443 int other_integral_value = rhs.raw() >> OtherFractionalBits;
444 int fractional_value = value_ & ((1 << fractional_bits) - 1); // Mask out the integral part
445 int other_fractional_value = rhs.raw() & ((1 << OtherFractionalBits) - 1); // Mask out the integral part
446
447 // Shift the fractional part if the number of fractional bits is different
448 if (fractional_bits > OtherFractionalBits) {
449 fractional_value >>= fractional_bits - OtherFractionalBits;
450 }
451 else {
452 other_fractional_value >>= OtherFractionalBits - fractional_bits;
453 }
454
455 if (integral_value < other_integral_value) {
456 return std::strong_ordering::less;
457 }
458 if (integral_value > other_integral_value) {
459 return std::strong_ordering::greater;
460 }
461 if (fractional_value < other_fractional_value) {
462 return std::strong_ordering::less;
463 }
464 if (fractional_value > other_fractional_value) {
465 return std::strong_ordering::greater;
466 }
467 return std::strong_ordering::equal;
468 }
469
471 [[gnu::always_inline]] constexpr FixedPoint MultiplyInt(const std::integral auto& rhs) const {
472 return FixedPoint::from_raw(value_ * static_cast<BaseType>(rhs));
473 }
474
476 [[gnu::always_inline]] constexpr FixedPoint DivideInt(const std::integral auto& rhs) const {
477 return FixedPoint::from_raw(value_ / static_cast<BaseType>(rhs));
478 }
479
480 [[gnu::always_inline]] constexpr FixedPoint operator*(const std::integral auto& rhs) const {
481 return MultiplyInt(rhs);
482 }
483
484 [[gnu::always_inline]] constexpr FixedPoint operator/(const std::integral auto& rhs) { return DivideInt(rhs); }
485
486 [[gnu::always_inline]] [[nodiscard]] constexpr int32_t integral() const {
487 return static_cast<int32_t>(value_ >> fractional_bits);
488 }
489
490 [[gnu::always_inline]] constexpr FixedPoint absolute() const noexcept {
491 if constexpr (fractional_bits == 31) {
492 // This converts the range -2^31 to 2^31 to the range 0-2^31
493 return from_raw((value_ / 2) + (1073741824));
494 }
495 else {
496 return from_raw(value_ < 0 ? -value_ : value_);
497 }
498 }
499
500private:
501 BaseType value_{0};
502};
503
505template <std::integral T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
507operator*(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
508 return rhs.MultiplyInt(lhs);
509}
510
511template <std::floating_point T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
513operator+(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
514 return rhs + lhs;
515}
516
517template <std::floating_point T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
519operator-(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
521}
522
523template <std::floating_point T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
525operator*(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
526 return rhs * lhs;
527}
528
530#ifdef __clang__
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;
536#else
537constexpr int32_t ONE_Q31 = FixedPoint<31>{1.f}.raw();
538constexpr float ONE_Q31f = static_cast<float>(ONE_Q31);
539constexpr int32_t ONE_Q16 = FixedPoint<16>{1.f}.raw() - 1;
540constexpr int32_t NEGATIVE_ONE_Q31 = FixedPoint<31>{-1.f}.raw();
541constexpr int32_t ONE_OVER_SQRT2_Q31 = FixedPoint<31>{1 / std::numbers::sqrt2}.raw();
542#endif
543
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.