Nugget
Loading...
Searching...
No Matches
fixed-point.hh
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2023 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27#pragma once
28
29#include <EASTL/functional.h>
30#include <stdint.h>
31
32#include <compare>
33#include <concepts>
34#include <type_traits>
35
36namespace psyqo {
37
38namespace FixedPointInternals {
39
40uint32_t iDiv(uint64_t rem, uint32_t base, unsigned scale);
41int32_t dDiv(int32_t a, int32_t b, unsigned scale);
42void printInt(uint32_t value, const eastl::function<void(char)>&, unsigned scale);
43
44} // namespace FixedPointInternals
45
69template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned Scale = 1 << precisionBits>
70 requires((precisionBits > 0) && (precisionBits < 32) && ((sizeof(T) == 4) || (sizeof(T) == 2) || sizeof(T) == 1))
71class FixedPoint {
72 using signedUpType = std::conditional<sizeof(T) == 4, int64_t, int32_t>::type;
73 using unsignedUpType = std::conditional<sizeof(T) == 4, uint64_t, uint32_t>::type;
74 using upType = std::conditional<std::is_signed<T>::value, signedUpType, unsignedUpType>::type;
75
76 public:
84 T value;
85 T raw() const { return value; }
86
91 static constexpr unsigned scale = Scale;
92
98 explicit constexpr FixedPoint(T integer, T fraction) : value(integer * scale + fraction) {
99 static_assert(sizeof(FixedPoint) == sizeof(T));
100 }
101
112 consteval FixedPoint(long double ld) {
113 bool negative = ld < 0;
114 T integer = negative ? -ld : ld;
115 T fraction = ld * scale - integer * scale + (negative ? -0.5 : 0.5);
116 value = integer * scale + fraction;
117 }
118
119 constexpr FixedPoint() : value(0) {}
120 constexpr FixedPoint(const FixedPoint&) = default;
121 constexpr FixedPoint(FixedPoint&&) = default;
122 constexpr FixedPoint& operator=(const FixedPoint&) = default;
123
124 enum Raw { RAW };
125 constexpr FixedPoint(T raw, Raw) : value(raw) {}
126
131 template <unsigned otherPrecisionBits = 12, std::integral U = int32_t>
132 explicit FixedPoint(FixedPoint<otherPrecisionBits, U> other) {
133 if constexpr (precisionBits == otherPrecisionBits) {
134 value = T(other.value);
135 } else if constexpr (precisionBits > otherPrecisionBits) {
136 value = T(other.value << (precisionBits - otherPrecisionBits));
137 } else if constexpr (precisionBits < otherPrecisionBits) {
138 value = T(other.value >> (otherPrecisionBits - precisionBits));
139 }
140 }
141
158 template <size_t factor = 1>
159 constexpr T integer() const {
160 if constexpr (std::is_signed<T>::value) {
161 if (value < 0) {
162 return T(value - scale / (2 * factor)) / T(scale / factor);
163 }
164 }
165 return T(value + scale / (2 * factor)) / T(scale / factor);
166 }
167
168 template <std::integral U>
169 constexpr U integer() const {
170 if constexpr (std::is_signed<T>::value) {
171 if (value < 0) {
172 return U((value - scale / 2) / scale);
173 }
174 }
175 return U(value + scale / 2) / U(scale);
176 }
177
189 template <std::integral U = T>
190 constexpr U floor() const {
191 if constexpr (std::is_signed<T>::value) {
192 if (value < 0) {
193 return U(value - scale + 1) / U(scale);
194 }
195 }
196 return U(value) / U(scale);
197 }
198
210 template <std::integral U = T>
211 constexpr U ceil() const {
212 if constexpr (std::is_signed<T>::value) {
213 if (value < 0) {
214 return U(value) / U(scale);
215 }
216 }
217 return U(value + scale - 1) / U(scale);
218 }
219
232 void print(const eastl::function<void(char)>& charPrinter) const {
233 T copy = value;
234 if constexpr (std::is_signed<T>::value) {
235 if (copy < 0) {
236 charPrinter('-');
237 copy = -copy;
238 }
239 }
240 FixedPointInternals::printInt(copy, charPrinter, scale);
241 }
242
243 constexpr FixedPoint abs() const {
244 FixedPoint ret = *this;
245 if constexpr (std::is_signed<T>::value) {
246 if (ret.value < 0) {
247 ret.value = -ret.value;
248 }
249 }
250 return ret;
251 }
252
253 constexpr FixedPoint operator+(FixedPoint other) const {
254 FixedPoint ret = *this;
255 ret.value += other.value;
256 return ret;
257 }
258
259 template <std::integral U>
260 constexpr FixedPoint operator+(U other) const {
261 FixedPoint ret = *this;
262 ret.value += other * scale;
263 return ret;
264 }
265
266 constexpr FixedPoint operator-(FixedPoint other) const {
267 FixedPoint ret = *this;
268 ret.value -= other.value;
269 return ret;
270 }
271
272 template <std::integral U>
273 constexpr FixedPoint operator-(U other) const {
274 FixedPoint ret = *this;
275 ret.value -= other * scale;
276 return ret;
277 }
278
279 constexpr FixedPoint operator*(FixedPoint other) const {
280 upType t = value;
281 t *= other.value;
282 t /= scale;
283 FixedPoint ret;
284 ret.value = t;
285 return ret;
286 }
287
288 template <std::integral U>
289 constexpr FixedPoint operator*(U other) const {
290 FixedPoint ret = *this;
291 ret.value *= other;
292 return ret;
293 }
294
295 constexpr FixedPoint operator/(FixedPoint other) const {
296 FixedPoint ret;
297 if constexpr (sizeof(T) == 4) {
298 if constexpr (std::is_signed<T>::value) {
299 ret.value = FixedPointInternals::dDiv(value, other.value, scale);
300 } else if constexpr (!std::is_signed<T>::value) {
301 ret.value = FixedPointInternals::iDiv(value, other.value, scale);
302 }
303 } else if constexpr (sizeof(T) < 4) {
304 upType t = value;
305 t *= scale;
306 t /= other.value;
307 ret.value = t;
308 }
309 return ret;
310 }
311
312 template <std::integral U>
313 constexpr FixedPoint operator/(U other) const {
314 FixedPoint ret = *this;
315 ret.value /= other;
316 return ret;
317 }
318
319 constexpr FixedPoint operator-() const {
320 FixedPoint ret = *this;
321 ret.value = -ret.value;
322 return ret;
323 }
324
325 constexpr FixedPoint& operator+=(FixedPoint other) {
326 value += other.value;
327 return *this;
328 }
329
330 template <std::integral U>
331 constexpr FixedPoint& operator+=(U other) {
332 value += other * scale;
333 return *this;
334 }
335
336 constexpr FixedPoint& operator-=(FixedPoint other) {
337 value -= other.value;
338 return *this;
339 }
340
341 template <std::integral U>
342 constexpr FixedPoint& operator-=(U other) {
343 value -= other * scale;
344 return *this;
345 }
346
347 constexpr FixedPoint& operator*=(FixedPoint other) {
348 upType t = value;
349 t *= other.value;
350 t /= scale;
351 value = t;
352 return *this;
353 }
354
355 template <std::integral U>
356 constexpr FixedPoint& operator*=(U other) {
357 value *= other;
358 return *this;
359 }
360
361 constexpr FixedPoint& operator/=(FixedPoint other) {
362 if constexpr (sizeof(T) == 4) {
363 if constexpr (std::is_signed<T>::value) {
364 value = FixedPointInternals::dDiv(value, other.value, scale);
365 } else if constexpr (!std::is_signed<T>::value) {
366 value = FixedPointInternals::iDiv(value, other.value, scale);
367 }
368 } else if constexpr (sizeof(T) == 2) {
369 upType t = value;
370 t *= scale;
371 t /= other.value;
372 value = t;
373 }
374 return *this;
375 }
376
377 template <std::integral U>
378 constexpr FixedPoint& operator/=(U other) {
379 value /= other;
380 return *this;
381 }
382
383 auto operator<=>(const FixedPoint& other) const = default;
384
385 constexpr FixedPoint operator<<(unsigned shift) const {
386 FixedPoint ret = *this;
387 ret.value <<= shift;
388 return ret;
389 }
390
391 constexpr FixedPoint operator>>(unsigned shift) const {
392 FixedPoint ret = *this;
393 ret.value >>= shift;
394 return ret;
395 }
396
397 constexpr FixedPoint& operator<<=(unsigned shift) {
398 value <<= shift;
399 return *this;
400 }
401
402 constexpr FixedPoint& operator>>=(unsigned shift) {
403 value >>= shift;
404 return *this;
405 }
406
407 constexpr FixedPoint operator++() {
408 value += scale;
409 return *this;
410 }
411
412 constexpr FixedPoint operator++(int) {
413 FixedPoint ret = *this;
414 value += scale;
415 return ret;
416 }
417
418 constexpr FixedPoint operator--() {
419 value -= scale;
420 return *this;
421 }
422
423 constexpr FixedPoint operator--(int) {
424 FixedPoint ret = *this;
425 value -= scale;
426 return ret;
427 }
428
429 constexpr bool operator!() const { return value == 0; }
430};
431
432template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
433 std::integral U = int32_t>
434constexpr FixedPoint<precisionBits, T, scale> operator+(U a, FixedPoint<precisionBits, T, scale> b) {
435 return b + a;
436}
437
438template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
439 std::integral U = int32_t>
440constexpr FixedPoint<precisionBits, T, scale> operator-(U a, FixedPoint<precisionBits, T, scale> b) {
441 return -b + a;
442}
443
444template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
445 std::integral U = int32_t>
446constexpr FixedPoint<precisionBits, T, scale> operator*(U a, FixedPoint<precisionBits, T, scale> b) {
447 return b * a;
448}
449
450template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
451 std::integral U = int32_t>
452constexpr FixedPoint<precisionBits, T, scale> operator/(U a, FixedPoint<precisionBits, T, scale> b) {
453 FixedPoint<precisionBits, T, scale> ret;
454 if constexpr (sizeof(T) == 4) {
455 if constexpr (std::is_signed<T>::value || std::is_signed<U>::value) {
456 ret.value = FixedPointInternals::dDiv(a * FixedPoint<precisionBits, T>::scale, b.raw(), scale);
457 } else if constexpr (!std::is_signed<T>::value && !std::is_signed<U>::value) {
458 ret.value = FixedPointInternals::iDiv(a * FixedPoint<precisionBits, T>::scale, b.raw(), scale);
459 }
460 } else if constexpr (sizeof(T) == 2) {
461 ret.value = a * FixedPoint<precisionBits, T>::scale / b.raw();
462 }
463 return ret;
464}
465
466namespace fixed_point_literals {
467
474consteval FixedPoint<> operator""_fp(long double value) { return value; }
475
476} // namespace fixed_point_literals
477
478} // namespace psyqo
uint32_t t
Definition cop0.c:79
uint32_t iDiv(uint64_t rem, uint32_t base, unsigned scale)
Definition fixed-point.cpp:29
int32_t dDiv(int32_t a, int32_t b, unsigned scale)
Definition fixed-point.cpp:59
void printInt(uint32_t value, const eastl::function< void(char)> &, unsigned scale)
Definition fixed-point.cpp:72
Definition cdrom-loader.hh:39
psyqo::AdvancedPad::Pad & operator++(psyqo::AdvancedPad::Pad &pad)
Definition advancedpad.hh:253
psyqo::AdvancedPad::Pad & operator--(psyqo::AdvancedPad::Pad &pad)
Definition advancedpad.hh:265
char b[9]
Definition string.c:47
static int value
Definition syscalls.h:534
static int ret
Definition syscalls.h:72
void uint32_t(classId, spec)