arduino-audio-tools
Loading...
Searching...
No Matches
PseudoFloat.h
Go to the documentation of this file.
1#pragma once
2
3#include <cmath>
4#include <cstdint>
5
6namespace audio_tools {
7
46 public:
47 constexpr PseudoFloat() = default;
48 constexpr PseudoFloat(int16_t mantissa, int16_t exponent)
49 : m_(mantissa), e_(exponent) {}
50 PseudoFloat(float f) { fromFloat(f); }
51 PseudoFloat(double d) { fromFloat((float)d); }
52 PseudoFloat(int i) { fromFloat((float)i); }
53
54 operator float() const { return toFloat(); }
55
57 return addAligned(m_, e_, o.m_, o.e_);
58 }
59 PseudoFloat operator-(PseudoFloat o) const { return *this + (-o); }
61 return PseudoFloat((int16_t)(-(int32_t)m_), e_);
62 }
63
65 int32_t prod = ((int32_t)m_ * (int32_t)o.m_) >> 15;
66 return normalize(prod, (int32_t)e_ + o.e_ + 15);
67 }
68
70 if (o.m_ == 0) {
71 // Match WORD2INT-style saturation elsewhere in this codebase: a very
72 // large (but finite, sign-matching) result instead of a hardware trap.
73 return PseudoFloat((int16_t)(m_ < 0 ? -32767 : 32767), (int16_t)30);
74 }
75 int32_t numerator = (int32_t)m_ << 15;
76 int32_t quotient = numerator / o.m_;
77 return normalize(quotient, (int32_t)e_ - o.e_ - 15);
78 }
79
80 PseudoFloat& operator+=(PseudoFloat o) { return *this = *this + o; }
81 PseudoFloat& operator-=(PseudoFloat o) { return *this = *this - o; }
82 PseudoFloat& operator*=(PseudoFloat o) { return *this = *this * o; }
83 PseudoFloat& operator/=(PseudoFloat o) { return *this = *this / o; }
84
85 bool operator<(PseudoFloat o) const { return toFloat() < o.toFloat(); }
86 bool operator>(PseudoFloat o) const { return toFloat() > o.toFloat(); }
87 bool operator<=(PseudoFloat o) const { return toFloat() <= o.toFloat(); }
88 bool operator>=(PseudoFloat o) const { return toFloat() >= o.toFloat(); }
89 bool operator==(PseudoFloat o) const { return m_ == o.m_ && e_ == o.e_; }
90 bool operator!=(PseudoFloat o) const { return !(*this == o); }
91
92 // PseudoFloat has both a converting constructor from float and a
93 // conversion operator to float, so `pseudoFloatValue * 0.7f` (and every
94 // other mixed op) would otherwise be ambiguous -- the compiler can't
95 // choose between converting the float to PseudoFloat (to use the member
96 // operator above) or converting the PseudoFloat to float (to use the
97 // built-in operator), and both need exactly one user-defined conversion.
98 // These exact-match overloads (no conversion needed for either operand)
99 // resolve that ambiguity, since the algorithm this class backs mixes
100 // float literals and PseudoFloat variables constantly.
101 PseudoFloat operator+(float o) const { return *this + PseudoFloat(o); }
102 PseudoFloat operator-(float o) const { return *this - PseudoFloat(o); }
103 PseudoFloat operator*(float o) const { return *this * PseudoFloat(o); }
104 PseudoFloat operator/(float o) const { return *this / PseudoFloat(o); }
105 bool operator<(float o) const { return *this < PseudoFloat(o); }
106 bool operator>(float o) const { return *this > PseudoFloat(o); }
107 bool operator<=(float o) const { return *this <= PseudoFloat(o); }
108 bool operator>=(float o) const { return *this >= PseudoFloat(o); }
109 bool operator==(float o) const { return *this == PseudoFloat(o); }
110 bool operator!=(float o) const { return *this != PseudoFloat(o); }
111
112 int16_t mantissa() const { return m_; }
113 int16_t exponent() const { return e_; }
114
115 private:
116 int16_t m_ = 0; // normalized magnitude in [16384, 32767] (0 iff value == 0)
117 int16_t e_ = 0; // value = m_ * 2^e_
118
119 void fromFloat(float f) {
120 if (f == 0.0f) {
121 m_ = 0;
122 e_ = 0;
123 return;
124 }
125 bool neg = f < 0;
126 double mag = neg ? -(double)f : (double)f;
127 int32_t e = 0;
128 while (mag >= 32768.0) {
129 mag *= 0.5;
130 e++;
131 }
132 while (mag < 16384.0) {
133 mag *= 2.0;
134 e--;
135 }
136 int16_t mag16 = (int16_t)mag;
137 m_ = neg ? (int16_t)(-(int32_t)mag16) : mag16;
138 e_ = (int16_t)e;
139 }
140
141 float toFloat() const {
142 return (float)((double)m_ * pow(2.0, (double)e_));
143 }
144
147 static PseudoFloat normalize(int32_t val, int32_t e) {
148 if (val == 0) return PseudoFloat((int16_t)0, (int16_t)0);
149 bool neg = val < 0;
150 int64_t mag = neg ? -(int64_t)val : (int64_t)val;
151 while (mag > 32767) {
152 mag >>= 1;
153 e++;
154 }
155 while (mag < 16384) {
156 mag <<= 1;
157 e--;
158 }
159 int16_t mi = (int16_t)(neg ? -mag : mag);
160 return PseudoFloat(mi, (int16_t)e);
161 }
162
165 static PseudoFloat addAligned(int16_t ma, int16_t ea, int16_t mb,
166 int16_t eb) {
167 if (ma == 0) return PseudoFloat(mb, eb);
168 if (mb == 0) return PseudoFloat(ma, ea);
169 int32_t a = ma, b = mb;
170 int32_t e;
171 if (ea >= eb) {
172 int shift = ea - eb;
173 b = (shift >= 31) ? 0 : (b >> shift);
174 e = ea;
175 } else {
176 int shift = eb - ea;
177 a = (shift >= 31) ? 0 : (a >> shift);
178 e = eb;
179 }
180 return normalize(a + b, e);
181 }
182};
183
184// Free-function overloads for `float op PseudoFloat` (float on the left),
185// for the same exact-match-ambiguity reason as the member float overloads
186// above.
187inline PseudoFloat operator+(float a, PseudoFloat b) { return PseudoFloat(a) + b; }
188inline PseudoFloat operator-(float a, PseudoFloat b) { return PseudoFloat(a) - b; }
189inline PseudoFloat operator*(float a, PseudoFloat b) { return PseudoFloat(a) * b; }
190inline PseudoFloat operator/(float a, PseudoFloat b) { return PseudoFloat(a) / b; }
191inline bool operator<(float a, PseudoFloat b) { return PseudoFloat(a) < b; }
192inline bool operator>(float a, PseudoFloat b) { return PseudoFloat(a) > b; }
193inline bool operator<=(float a, PseudoFloat b) { return PseudoFloat(a) <= b; }
194inline bool operator>=(float a, PseudoFloat b) { return PseudoFloat(a) >= b; }
195inline bool operator==(float a, PseudoFloat b) { return PseudoFloat(a) == b; }
196inline bool operator!=(float a, PseudoFloat b) { return PseudoFloat(a) != b; }
197
198} // namespace audio_tools
Software "pseudo-float": a real number represented as a signed 16-bit mantissa plus a 16-bit exponent...
Definition PseudoFloat.h:45
PseudoFloat operator+(float o) const
Definition PseudoFloat.h:101
bool operator<=(float o) const
Definition PseudoFloat.h:107
constexpr PseudoFloat(int16_t mantissa, int16_t exponent)
Definition PseudoFloat.h:48
int16_t exponent() const
Definition PseudoFloat.h:113
bool operator>(float o) const
Definition PseudoFloat.h:106
PseudoFloat & operator/=(PseudoFloat o)
Definition PseudoFloat.h:83
PseudoFloat(int i)
Definition PseudoFloat.h:52
bool operator==(float o) const
Definition PseudoFloat.h:109
PseudoFloat operator*(PseudoFloat o) const
Definition PseudoFloat.h:64
bool operator>(PseudoFloat o) const
Definition PseudoFloat.h:86
constexpr PseudoFloat()=default
int16_t mantissa() const
Definition PseudoFloat.h:112
PseudoFloat & operator+=(PseudoFloat o)
Definition PseudoFloat.h:80
PseudoFloat & operator*=(PseudoFloat o)
Definition PseudoFloat.h:82
PseudoFloat operator/(float o) const
Definition PseudoFloat.h:104
bool operator<(float o) const
Definition PseudoFloat.h:105
PseudoFloat operator+(PseudoFloat o) const
Definition PseudoFloat.h:56
bool operator>=(PseudoFloat o) const
Definition PseudoFloat.h:88
PseudoFloat operator-(float o) const
Definition PseudoFloat.h:102
PseudoFloat(double d)
Definition PseudoFloat.h:51
PseudoFloat(float f)
Definition PseudoFloat.h:50
bool operator<(PseudoFloat o) const
Definition PseudoFloat.h:85
bool operator==(PseudoFloat o) const
Definition PseudoFloat.h:89
PseudoFloat operator/(PseudoFloat o) const
Definition PseudoFloat.h:69
bool operator>=(float o) const
Definition PseudoFloat.h:108
PseudoFloat operator*(float o) const
Definition PseudoFloat.h:103
bool operator<=(PseudoFloat o) const
Definition PseudoFloat.h:87
PseudoFloat & operator-=(PseudoFloat o)
Definition PseudoFloat.h:81
PseudoFloat operator-(PseudoFloat o) const
Definition PseudoFloat.h:59
bool operator!=(PseudoFloat o) const
Definition PseudoFloat.h:90
PseudoFloat operator-() const
Definition PseudoFloat.h:60
bool operator!=(float o) const
Definition PseudoFloat.h:110
uint8_t pow(uint8_t x, intmax_t power)
Definition gf.hpp:111
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
PseudoFloat operator-(float a, PseudoFloat b)
Definition PseudoFloat.h:188
bool operator==(float a, PseudoFloat b)
Definition PseudoFloat.h:195
bool operator<=(float a, PseudoFloat b)
Definition PseudoFloat.h:193
PseudoFloat operator*(float a, PseudoFloat b)
Definition PseudoFloat.h:189
bool operator>(float a, PseudoFloat b)
Definition PseudoFloat.h:192
bool operator!=(float a, PseudoFloat b)
Definition PseudoFloat.h:196
bool operator<(float a, PseudoFloat b)
Definition PseudoFloat.h:191
PseudoFloat operator/(float a, PseudoFloat b)
Definition PseudoFloat.h:190
bool operator>=(float a, PseudoFloat b)
Definition PseudoFloat.h:194
PseudoFloat operator+(float a, PseudoFloat b)
Definition PseudoFloat.h:187