Deluge Firmware 1.3.0
Build date: 2025.04.16
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]] constexpr FixedPoint(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 value_ = std::bit_cast<int32_t>(value); // NOLINT
132 return;
133 }
134#endif
135
136 value *= static_cast<double>(FixedPoint::one());
137 // convert from floating-point to fixed point
138 if constexpr (rounded) {
139 value = std::round(value);
140 }
141
142 // saturate
143 value_ = static_cast<BaseType>(std::clamp<int64_t>(
144 static_cast<int64_t>(value), std::numeric_limits<BaseType>::min(), std::numeric_limits<BaseType>::max()));
145 }
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]] constexpr FixedPoint(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 value_ = static_cast<BaseType>(output);
178 return;
179 }
180#endif
181 value *= static_cast<double>(FixedPoint::one());
182 // convert from floating-point to fixed point
183 if constexpr (rounded) {
184 value = std::round(value);
185 }
186
187 // saturate
188 value_ = static_cast<BaseType>(std::clamp<int64_t>(
189 static_cast<int64_t>(value), std::numeric_limits<BaseType>::min(), std::numeric_limits<BaseType>::max()));
190 }
191
194 [[gnu::always_inline]] explicit constexpr operator double() const noexcept {
195#if __ARM_ARCH_7A__ && !defined(__clang__)
196 if !consteval {
197 auto output = std::bit_cast<double>((int64_t)value_);
198 asm("vcvt.f64.s32 %0, %1, %2" : "=w"(output) : "w"(output), "I"(fractional_bits));
199 return output;
200 }
201#endif
202
203 return static_cast<double>(value_) / FixedPoint::one();
204 }
205
207 template <std::size_t OutputFractionalBits>
208 [[gnu::always_inline]] constexpr FixedPoint<OutputFractionalBits> as() const {
209 return static_cast<FixedPoint<OutputFractionalBits>>(*this);
210 }
211
213 template <std::signed_integral T>
214 constexpr explicit operator T() const noexcept {
215 if constexpr (rounded) {
216 // round to nearest integer
217 return static_cast<T>(roundToBit<fractional_bits>(value_) >> fractional_bits);
218 }
219 else {
220 // return the integral
221 return integral();
222 }
223 }
224
225 constexpr explicit operator bool() const noexcept { return value_ != 0; }
226
228 [[gnu::always_inline]] [[nodiscard]] constexpr FixedPoint operator-() const { return from_raw(-value_); }
229
231 [[gnu::always_inline]] [[nodiscard]] constexpr BaseType raw() const noexcept { return value_; }
232
234 [[gnu::always_inline]] static constexpr FixedPoint from_raw(BaseType raw) noexcept {
235 FixedPoint result{};
236 result.value_ = raw;
237 return result;
238 }
239
242 [[gnu::always_inline]] constexpr FixedPoint operator+(const FixedPoint& rhs) const {
243 return from_raw(add_saturate(value_, rhs.value_));
244 }
245
248 [[gnu::always_inline]] constexpr FixedPoint operator+=(const FixedPoint& rhs) {
249 value_ = add_saturate(value_, rhs.value_);
250 return *this;
251 }
252
255 [[gnu::always_inline]] constexpr FixedPoint operator-(const FixedPoint& rhs) const {
256 return from_raw(subtract_saturate(value_, rhs.value_));
257 }
258
261 [[gnu::always_inline]] constexpr FixedPoint operator-=(const FixedPoint& rhs) {
262 value_ = subtract_saturate(value_, rhs.value_);
263 return *this;
264 }
265
268 [[gnu::always_inline]] constexpr FixedPoint operator*(const FixedPoint& rhs) const {
269 if constexpr (fast_approximation && fractional_bits > 16) {
270 // less than 16 would mean no fractional bits remain after right shift by 32
271 constexpr int32_t shift = fractional_bits - ((fractional_bits * 2) - 32);
272 return from_raw(signed_most_significant_word_multiply(value_, rhs.value_) << shift);
273 }
274 else if constexpr (rounded) {
275 IntermediateType value = (static_cast<IntermediateType>(value_) * rhs.value_) >> (fractional_bits - 1);
276 return from_raw(static_cast<BaseType>((value >> 1) + (value % 2)));
277 }
278 else {
279 IntermediateType value = (static_cast<IntermediateType>(value_) * rhs.value_) >> fractional_bits;
280 return from_raw(static_cast<BaseType>(value));
281 }
282 }
283
286 [[gnu::always_inline]] constexpr FixedPoint operator*=(const FixedPoint& rhs) {
287 value_ = this->operator*(rhs).value_;
288 return *this;
289 }
290
293 template <std::size_t OutputFractionalBits = FractionalBits, std::size_t OtherFractionalBits, bool OtherRounded,
294 bool OtherApproximating>
295 requires(OtherRounded == Rounded && OtherApproximating == FastApproximation)
298 if constexpr (fast_approximation) {
299 constexpr int32_t l_shift = OutputFractionalBits - ((FractionalBits + OtherFractionalBits) - 32);
300 static_assert(l_shift < 32 && l_shift > -32);
301 BaseType value = signed_most_significant_word_multiply(value_, rhs.raw());
302 return from_raw(l_shift > 0 ? value << l_shift : value >> -l_shift);
303 }
304
305 constexpr int32_t r_shift = (FractionalBits + OtherFractionalBits) - OutputFractionalBits;
306 if constexpr (rounded) {
307 IntermediateType value = (static_cast<IntermediateType>(value_) * rhs.raw())
308 >> (r_shift - 1); // At this point Q is FractionalBits + OtherFractionalBits
309 return from_raw(static_cast<BaseType>((value / 2) + (value % 2)));
310 }
311
312 IntermediateType value = (static_cast<IntermediateType>(value_) * rhs.raw()) >> r_shift;
313 return from_raw(static_cast<BaseType>(value));
314 }
315
318 template <std::size_t OtherFractionalBits>
319 [[gnu::always_inline]] constexpr FixedPoint operator*=(const FixedPoint<OtherFractionalBits>& rhs) {
320 value_ = this->operator*(rhs).value_;
321 return *this;
322 }
323
326 [[gnu::always_inline]] constexpr FixedPoint operator/(const FixedPoint& rhs) const {
327 if constexpr (rounded) {
328 IntermediateType value = (static_cast<IntermediateType>(value_) << (fractional_bits + 1)) / rhs.value_;
329 return from_raw(static_cast<BaseType>((value / 2) + (value % 2)));
330 }
331 else {
332 IntermediateType value = (static_cast<IntermediateType>(value_) << fractional_bits) / rhs.value_;
333 return from_raw(static_cast<BaseType>(value));
334 }
335 }
336
339 template <std::size_t OtherFractionalBits,
340 std::size_t ResultFractionalBits = std::max(FractionalBits, OtherFractionalBits)
341 - std::min(FractionalBits, OtherFractionalBits)>
342
343 requires(ResultFractionalBits < std::max(FractionalBits, OtherFractionalBits))
344 && (ResultFractionalBits > std::min(FractionalBits, OtherFractionalBits))
347 if (rhs.raw() == 0) {
348 return FixedPoint<ResultFractionalBits>::from_raw(std::numeric_limits<BaseType>::max());
349 }
350
351 constexpr int shift = static_cast<int32_t>(FractionalBits) - OtherFractionalBits;
352 IntermediateType result{};
353 if constexpr (shift > 0) {
354 // this means we have more fractional bits than the divisor
355 result = (static_cast<IntermediateType>(value_) << shift) / rhs.raw();
356 }
357 else if constexpr (shift < 0) {
358 // this means we have less fractional bits than the divisor
359 result = (static_cast<IntermediateType>(value_) / (rhs.raw() << -shift));
360 }
361 else {
362 // same number of fractional bits
363 result = static_cast<IntermediateType>(value_) / rhs.raw();
364 }
365 size_t result_shift = std::max(FractionalBits, OtherFractionalBits) - ResultFractionalBits;
366
367 if constexpr (rounded) {
368 // round the result
369 result += (1 << (result_shift - 1)); // add half to round
370 }
371 // shift to get the correct number of fractional bits
373 }
374
377 [[gnu::always_inline]] constexpr FixedPoint operator/=(const FixedPoint& rhs) {
378 value_ = this->operator/(rhs).value_;
379 return *this;
380 }
381
384 template <std::size_t OtherFractionalBitsA, std::size_t OtherFractionalBitsB>
386 const FixedPoint<OtherFractionalBitsB>& b) const {
387 // ensure that the number of fractional bits in the addend is equal to the sum of the number of fractional bits
388 // in multiplicands, minus 32 (due to right shift) before using smmla/smmlar
389 if constexpr (fast_approximation && (OtherFractionalBitsA + OtherFractionalBitsB) - 32 == FractionalBits) {
391 }
392 else {
393 return *this + static_cast<FixedPoint>(a * b);
394 }
395 }
396
399 [[nodiscard]] constexpr FixedPoint MultiplyAdd(const FixedPoint& a, const FixedPoint& b) const {
400 if constexpr (fast_approximation && (((fractional_bits * 2) - 32) == (fractional_bits - 1))) {
401 // fractional_bits - 1 is due to the left shift
402 return from_raw(signed_most_significant_word_multiply_add(value_, a.raw(), b.raw()) << 1);
403 }
404 else {
405 return *this + (a * b);
406 }
407 }
408
410 [[gnu::always_inline]] constexpr bool operator==(const FixedPoint& rhs) const noexcept {
411 return value_ == rhs.value_;
412 }
413
415 constexpr std::strong_ordering operator<=>(const FixedPoint& rhs) const noexcept { return value_ <=> rhs.value_; }
416
418 template <std::size_t OtherFractionalBits>
419 constexpr bool operator==(const FixedPoint<OtherFractionalBits>& rhs) const noexcept {
420 int integral_value = value_ >> fractional_bits;
421 int other_integral_value = rhs.raw() >> OtherFractionalBits;
422 int fractional_value = value_ & ((1 << fractional_bits) - 1); // Mask out the integral part
423 int other_fractional_value = rhs.raw() & ((1 << OtherFractionalBits) - 1); // Mask out the integral parts
424
425 // Shift the fractional part if the number of fractional bits is different
426 if constexpr (fractional_bits > OtherFractionalBits) {
427 fractional_value >>= fractional_bits - OtherFractionalBits;
428 }
429 else {
430 other_fractional_value >>= OtherFractionalBits - fractional_bits;
431 }
432
433 return integral_value == other_integral_value && fractional_value == other_fractional_value;
434 }
435
437 template <std::size_t OtherFractionalBits>
438 constexpr std::strong_ordering operator<=>(const FixedPoint<OtherFractionalBits>& rhs) const noexcept {
439 // Compare integral and fractional components separately
440 int integral_value = value_ >> fractional_bits;
441 int other_integral_value = rhs.raw() >> OtherFractionalBits;
442 int fractional_value = value_ & ((1 << fractional_bits) - 1); // Mask out the integral part
443 int other_fractional_value = rhs.raw() & ((1 << OtherFractionalBits) - 1); // Mask out the integral part
444
445 // Shift the fractional part if the number of fractional bits is different
446 if (fractional_bits > OtherFractionalBits) {
447 fractional_value >>= fractional_bits - OtherFractionalBits;
448 }
449 else {
450 other_fractional_value >>= OtherFractionalBits - fractional_bits;
451 }
452
453 if (integral_value < other_integral_value) {
454 return std::strong_ordering::less;
455 }
456 if (integral_value > other_integral_value) {
457 return std::strong_ordering::greater;
458 }
459 if (fractional_value < other_fractional_value) {
460 return std::strong_ordering::less;
461 }
462 if (fractional_value > other_fractional_value) {
463 return std::strong_ordering::greater;
464 }
465 return std::strong_ordering::equal;
466 }
467
469 template <typename T>
470 requires std::floating_point<T>
471 [[gnu::always_inline]] constexpr bool operator==(const T& rhs) const noexcept {
472 return value_ == FixedPoint{rhs}.value_;
473 }
474
476 template <std::integral T>
477 [[gnu::always_inline]] constexpr FixedPoint MultiplyInt(const T& rhs) const {
478 return FixedPoint::from_raw(value_ * static_cast<BaseType>(rhs));
479 }
480
482 template <std::integral T>
483 [[gnu::always_inline]] constexpr FixedPoint DivideInt(const T& rhs) const {
484 return FixedPoint::from_raw(value_ / static_cast<BaseType>(rhs));
485 }
486
487 template <std::integral T>
488 [[gnu::always_inline]] constexpr FixedPoint operator*(const T& rhs) const {
489 return MultiplyInt(rhs);
490 }
491
492 template <std::integral T>
493 [[gnu::always_inline]] constexpr FixedPoint operator/(const T& rhs) {
494 return DivideInt(rhs);
495 }
496
497 [[gnu::always_inline]] [[nodiscard]] constexpr int32_t integral() const {
498 return static_cast<int32_t>(value_ >> fractional_bits);
499 }
500
501 [[gnu::always_inline]] constexpr FixedPoint absolute() const noexcept {
502 if constexpr (fractional_bits == 31) {
503 // This converts the range -2^31 to 2^31 to the range 0-2^31
504 return from_raw((value_ / 2) + (1073741824));
505 }
506 else {
507 return from_raw(value_ < 0 ? -value_ : value_);
508 }
509 }
510
511private:
512 BaseType value_{0};
513};
514
516template <std::integral T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
518operator*(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
519 return rhs.MultiplyInt(lhs);
520}
521
522template <std::floating_point T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
524operator+(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
525 return rhs + lhs;
526}
527
528template <std::floating_point T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
530operator-(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
532}
533
534template <std::floating_point T, std::size_t FractionalBits, bool Rounded, bool FastApproximation>
536operator*(const T& lhs, const FixedPoint<FractionalBits, Rounded, FastApproximation>& rhs) {
537 return rhs * lhs;
538}
539
541#ifdef __clang__
542constexpr int32_t ONE_Q31 = std::numeric_limits<int32_t>::max();
543constexpr float ONE_Q31f = static_cast<float>(ONE_Q31);
544constexpr int32_t ONE_Q16 = std::numeric_limits<uint16_t>::max();
545constexpr int32_t NEGATIVE_ONE_Q31 = std::numeric_limits<int32_t>::min();
546constexpr int32_t ONE_OVER_SQRT2_Q31 = ONE_Q31 / std::numbers::sqrt2;
547#else
548constexpr int32_t ONE_Q31 = FixedPoint<31>{1.f}.raw();
549constexpr float ONE_Q31f = static_cast<float>(ONE_Q31);
550constexpr int32_t ONE_Q16 = FixedPoint<16>{1.f}.raw() - 1;
551constexpr int32_t NEGATIVE_ONE_Q31 = FixedPoint<31>{-1.f}.raw();
552constexpr int32_t ONE_OVER_SQRT2_Q31 = FixedPoint<31>{1 / std::numbers::sqrt2}.raw();
553#endif
554
555static_assert(ONE_Q31 == std::numeric_limits<int32_t>::max());
556static_assert(ONE_Q31f == 1.0f * std::numeric_limits<int32_t>::max());
557static_assert(ONE_Q16 == std::numeric_limits<uint16_t>::max());
558static_assert(NEGATIVE_ONE_Q31 == std::numeric_limits<int32_t>::min());
559static_assert(ONE_OVER_SQRT2_Q31 == 1518500249);
Fixed point number with a configurable number of fractional bits.
Definition fixedpoint.h:47
constexpr bool operator==(const FixedPoint &rhs) const noexcept
Equality operator.
Definition fixedpoint.h:410
constexpr FixedPoint operator*=(const FixedPoint< OtherFractionalBits > &rhs)
Multiplication operator Multiply two fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:319
constexpr FixedPoint DivideInt(const T &rhs) const
Divide by an integral type.
Definition fixedpoint.h:483
constexpr FixedPoint(float value) noexcept
Convert from a float to a fixed point number.
Definition fixedpoint.h:127
constexpr std::strong_ordering operator<=>(const FixedPoint &rhs) const noexcept
Three-way comparison operator.
Definition fixedpoint.h:415
constexpr FixedPoint operator/(const FixedPoint &rhs) const
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:326
constexpr float to_float() const noexcept
Explicit conversion to float.
Definition fixedpoint.h:158
constexpr bool operator==(const T &rhs) const noexcept
Equality operator for integers and floating point numbers.
Definition fixedpoint.h:471
constexpr FixedPoint(T value) noexcept
Convert an integer to a fixed point number.
Definition fixedpoint.h:123
constexpr FixedPoint< OutputFractionalBits > as() const
Convert to a fixed point number with a different number of fractional bits.
Definition fixedpoint.h:208
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:385
constexpr FixedPoint operator/=(const FixedPoint &rhs)
Division operator Divide two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:377
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:346
constexpr bool operator==(const FixedPoint< OtherFractionalBits > &rhs) const noexcept
Equality operator for fixed point numbers with different number of fractional bits.
Definition fixedpoint.h:419
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:242
constexpr FixedPoint operator-() const
Negation operator.
Definition fixedpoint.h:228
constexpr FixedPoint operator*(const FixedPoint &rhs) const
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:268
constexpr BaseType raw() const noexcept
Get the internal value.
Definition fixedpoint.h:231
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:438
static constexpr FixedPoint from_raw(BaseType raw) noexcept
Construct from a raw value.
Definition fixedpoint.h:234
constexpr FixedPoint operator-(const FixedPoint &rhs) const
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:255
constexpr FixedPoint operator*=(const FixedPoint &rhs)
Multiplication operator Multiply two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:286
constexpr FixedPoint(double value) noexcept
Convert from a double to a fixed point number.
Definition fixedpoint.h:172
constexpr FixedPoint operator+=(const FixedPoint &rhs)
Addition operator Add two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:248
constexpr FixedPoint MultiplyInt(const T &rhs) const
Multiply by an integral type.
Definition fixedpoint.h:477
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:399
constexpr FixedPoint operator-=(const FixedPoint &rhs)
Subtraction operator Subtract two fixed point numbers with the same number of fractional bits.
Definition fixedpoint.h:261
constexpr FixedPoint()=default
Default constructor.