Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Fixed16.hxx
Go to the documentation of this file.
1
35#ifndef _UTILS_FIXED16_HXX_
36#define _UTILS_FIXED16_HXX_
37
38#include <stdint.h>
39
40#include "utils/macros.h"
41
43{
44public:
51 constexpr Fixed16(int16_t integer, uint16_t frac = 0)
52 : value_(((integer < 0 ? -integer : integer) << 16) | frac)
53 , sign_(integer < 0 ? 1 : 0)
54 {
55 }
56
57 enum FromDouble
58 {
59 FROM_DOUBLE
60 };
61
65 constexpr Fixed16(FromDouble, double value)
66 : value_(value < 0 ? -value * 65536 + 0.5 : value * 65536 + 0.5)
67 , sign_(value < 0 ? 1 : 0)
68 {
69 // it would be nice to make this work:
70 // static_assert(value < 32767 && value > -32767,
71 // "fixed16 constructor out of range");
72 }
73
74 Fixed16(const Fixed16 &o) = default;
75 Fixed16 &operator=(const Fixed16 &o) = default;
76
77 Fixed16 &operator+=(Fixed16 o)
78 {
79 from_int(to_int() + o.to_int());
80 return *this;
81 }
82
83 template <class T> Fixed16 operator+(T o) const
84 {
85 Fixed16 ret(*this);
86 ret += o;
87 return ret;
88 }
89
90 Fixed16 &operator-=(Fixed16 o)
91 {
92 from_int(to_int() - o.to_int());
93 return *this;
94 }
95
96 template <typename T> Fixed16 operator-(T o) const
97 {
98 Fixed16 ret(*this);
99 ret -= o;
100 return ret;
101 }
102
103 Fixed16 &operator*=(Fixed16 o)
104 {
105 uint64_t v = value_;
106 v *= o.value_;
107 v >>= 16;
108 value_ = v;
109 sign_ ^= o.sign_;
110 return *this;
111 }
112
113 template <typename T> Fixed16 operator*(T o) const
114 {
115 Fixed16 ret(*this);
116 ret *= o;
117 return ret;
118 }
119
120 Fixed16 &operator/=(Fixed16 o)
121 {
122 uint64_t v = value_;
123 v <<= 32;
124 v /= o.value_;
125 v >>= 16;
126 value_ = v;
127 sign_ ^= o.sign_;
128 return *this;
129 }
130
131 template <typename T> Fixed16 operator/(T o) const
132 {
133 Fixed16 ret(*this);
134 ret /= o;
135 return ret;
136 }
137
140 {
141 return to_key() < o.to_key();
142 }
143
146 {
147 return to_key() <= o.to_key();
148 }
149
152 {
153 return to_key() > o.to_key();
154 }
155
158 {
159 return to_key() >= o.to_key();
160 }
161
164 {
165 return to_key() == o.to_key();
166 }
167
170 {
171 return to_key() != o.to_key();
172 }
173
182 {
183 const Fixed16* coeffs;
184 uint16_t f;
185 if (o.is_positive())
186 {
187 // multiplying
188 value_ <<= o.trunc();
189 f = o.frac();
190 static constexpr const Fixed16 pown[6] = {
191 {FROM_DOUBLE, 1.4142135623730951}, // 2^(1/2)
192 {FROM_DOUBLE, 1.1892071150027210}, // 2^(1/4)
193 {FROM_DOUBLE, 1.0905077326652577}, // 2^(1/8)
194 {FROM_DOUBLE, 1.0442737824274138}, // 2^(1/16)
195 {FROM_DOUBLE, 1.0218971486541166}, // 2^(1/32)
196 {FROM_DOUBLE, 1.0108892860517005}}; // 2^(1/64)
197 coeffs = pown;
198 }
199 else
200 {
201 // dividing
202 o.negate();
203 value_ >>= o.trunc();
204 f = o.frac();
205 static constexpr const Fixed16 pown[6] = {
206 {FROM_DOUBLE, 0.7071067811865476}, // 2^(-1/2)
207 {FROM_DOUBLE, 0.8408964152537145}, // 2^(-1/4)
208 {FROM_DOUBLE, 0.9170040432046712}, // 2^(-1/8)
209 {FROM_DOUBLE, 0.9576032806985737}, // 2^(-1/16)
210 {FROM_DOUBLE, 0.9785720620877001}, // 2^(-1/32)
211 {FROM_DOUBLE, 0.9892280131939755}}; // 2^(-1/64)
212 coeffs = pown;
213 }
214 for (unsigned idx = 0, bit = 0x8000; idx < 6; ++idx, bit >>= 1)
215 {
216 if (f & bit)
217 {
218 *this *= coeffs[idx];
219 }
220 }
221 return *this;
222 }
223
225 int16_t round() const {
226 int16_t b = (value_ + 0x8000) >> 16;
227 if (sign_) return -b;
228 return b;
229 }
230
232 int16_t trunc() const
233 {
234 int16_t b = value_ >> 16;
235 if (sign_) return -b;
236 return b;
237 }
238
242 uint16_t frac() const
243 {
244 return value_ & 0xffff;
245 }
246
247 float to_float() const
248 {
249 if (!value_) {
250 if (sign_)
251 {
252 return -0.0f;
253 }
254 else
255 {
256 return 0.0f;
257 }
258 }
259 uint32_t f = 0;
260 if (sign_) f |= 0x80000000u;
261 int lz = __builtin_clz(value_);
262 if (lz <= 8)
263 {
264 HASSERT(((value_ >> (8 - lz)) & 0xFF800000U) == 0x800000U);
265 f |= (value_ >> (8 - lz)) & 0x7FFFFF;
266 }
267 else
268 {
269 HASSERT(((value_ << (lz - 8)) & 0xFF800000U) == 0x800000U);
270 f |= (value_ << (lz - 8)) & 0x7FFFFF;
271 }
272 uint32_t exp = (127 + 15 - lz) & 0xFF;
273 f |= exp << 23;
274 return *reinterpret_cast<float *>(&f);
275 }
276
277 /* uint16_t to_float16() {
278 if (!value_) return 0;
279
280 }*/
281
282 bool is_positive() const {
283 return sign_ == 0;
284 }
285
286 void negate() {
287 sign_ ^= 1;
288 }
289
291 int32_t to_key()
292 {
293 return to_int();
294 }
295
296private:
298 int32_t to_int() const
299 {
300 int32_t r = value_;
301 if (sign_)
302 {
303 return -r;
304 }
305 else
306 {
307 return r;
308 }
309 }
310
312 void from_int(int32_t v) {
313 if (v<0) {
314 sign_ = 1;
315 v = -v;
316 } else {
317 sign_ = 0;
318 }
319 value_ = v & 0x7fffffffu;
320 }
321
322 uint32_t value_ : 31;
323 uint32_t sign_ : 1;
324};
325
326#endif // _UTILS_FIXED16_HXX_
bool operator<(Fixed16 o)
Comparison operator.
Definition Fixed16.hxx:139
bool operator!=(Fixed16 o)
Comparison operator.
Definition Fixed16.hxx:169
int32_t to_int() const
Translates the current value to a signed fixed-point 32-bit integer.
Definition Fixed16.hxx:298
int32_t to_key()
Turns the value into a comparison key.
Definition Fixed16.hxx:291
bool operator>=(Fixed16 o)
Comparison operator.
Definition Fixed16.hxx:157
bool operator<=(Fixed16 o)
Comparison operator.
Definition Fixed16.hxx:145
bool operator==(Fixed16 o)
Comparison operator.
Definition Fixed16.hxx:163
constexpr Fixed16(FromDouble, double value)
Constructs a Fixed16.
Definition Fixed16.hxx:65
Fixed16 & mulpow2(Fixed16 o)
Multiplies *this with pow(2, o).
Definition Fixed16.hxx:181
int16_t round() const
Definition Fixed16.hxx:225
void from_int(int32_t v)
Overwrites the current value from a signed fixed-point 32-bit integer.
Definition Fixed16.hxx:312
uint16_t frac() const
Definition Fixed16.hxx:242
constexpr Fixed16(int16_t integer, uint16_t frac=0)
Constructs a Fixed16.
Definition Fixed16.hxx:51
bool operator>(Fixed16 o)
Comparison operator.
Definition Fixed16.hxx:151
int16_t trunc() const
Definition Fixed16.hxx:232
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138