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
40void printInt(uint32_t value, const eastl::function<void(char)>&, unsigned scale);
41
42constexpr uint32_t iDiv(uint64_t rem, uint32_t base, unsigned scale) {
43 rem *= scale;
44 uint64_t b = base;
45 uint64_t res, d = 1;
46 uint32_t high = rem >> 32;
47
48 res = 0;
49 if (high >= base) {
50 high /= base;
51 res = static_cast<uint64_t>(high) << 32;
52 rem -= static_cast<uint64_t>(high * base) << 32;
53 }
54
55 while (static_cast<int64_t>(b) > 0 && b < rem) {
56 b = b + b;
57 d = d + d;
58 }
59
60 do {
61 if (rem >= b) {
62 rem -= b;
63 res += d;
64 }
65 b >>= 1;
66 d >>= 1;
67 } while (d);
68
69 return res;
70}
71
72constexpr int32_t dDiv(int32_t a, int32_t b, unsigned scale) {
73 int s = 1;
74 if (a < 0) {
75 a = -a;
76 s = -1;
77 }
78 if (b < 0) {
79 b = -b;
80 s = -s;
81 }
82 return iDiv(a, b, scale) * s;
83}
84
85} // namespace FixedPointInternals
86
110template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned Scale = 1 << precisionBits>
111 requires((precisionBits > 0) && (precisionBits < 32) && ((sizeof(T) == 4) || (sizeof(T) == 2) || sizeof(T) == 1))
112class FixedPoint {
113 using signedUpType = std::conditional<sizeof(T) == 4, int64_t, int32_t>::type;
114 using unsignedUpType = std::conditional<sizeof(T) == 4, uint64_t, uint32_t>::type;
115 using upType = std::conditional<std::is_signed<T>::value, signedUpType, unsignedUpType>::type;
116
117 public:
125 T value;
126 T raw() const { return value; }
127
132 static constexpr unsigned scale = Scale;
133
139 explicit constexpr FixedPoint(T integer, T fraction) : value(integer * scale + fraction) {
140 static_assert(sizeof(FixedPoint) == sizeof(T));
141 }
142
153 consteval FixedPoint(long double ld) {
154 bool negative = ld < 0;
155 T integer = negative ? -ld : ld;
156 T fraction = ld * scale - integer * scale + (negative ? -0.5 : 0.5);
157 value = integer * scale + fraction;
158 }
159
160 constexpr FixedPoint() : value(0) {}
161 constexpr FixedPoint(const FixedPoint&) = default;
162 constexpr FixedPoint(FixedPoint&&) = default;
163 constexpr FixedPoint& operator=(const FixedPoint&) = default;
164
165 enum Raw { RAW };
166 constexpr FixedPoint(T raw, Raw) : value(raw) {}
167
172 template <unsigned otherPrecisionBits = 12, std::integral U = int32_t>
173 explicit FixedPoint(FixedPoint<otherPrecisionBits, U> other) {
174 if constexpr (precisionBits == otherPrecisionBits) {
175 value = T(other.value);
176 } else if constexpr (precisionBits > otherPrecisionBits) {
177 value = T(other.value << (precisionBits - otherPrecisionBits));
178 } else if constexpr (precisionBits < otherPrecisionBits) {
179 value = T(other.value >> (otherPrecisionBits - precisionBits));
180 }
181 }
182
199 template <size_t factor = 1>
200 constexpr T integer() const {
201 if constexpr (std::is_signed<T>::value) {
202 if (value < 0) {
203 return T(value - scale / (2 * factor)) / T(scale / factor);
204 }
205 }
206 return T(value + scale / (2 * factor)) / T(scale / factor);
207 }
208
209 template <std::integral U>
210 constexpr U integer() const {
211 if constexpr (std::is_signed<T>::value) {
212 if (value < 0) {
213 return U((value - scale / 2) / scale);
214 }
215 }
216 return U((value + scale / 2) / scale);
217 }
218
230 template <std::integral U = T>
231 constexpr U floor() const {
232 if constexpr (std::is_signed<T>::value) {
233 if (value < 0) {
234 return U(value - scale + 1) / U(scale);
235 }
236 }
237 return U(value) / U(scale);
238 }
239
251 template <std::integral U = T>
252 constexpr U ceil() const {
253 if constexpr (std::is_signed<T>::value) {
254 if (value < 0) {
255 return U(value) / U(scale);
256 }
257 }
258 return U(value + scale - 1) / U(scale);
259 }
260
273 void print(const eastl::function<void(char)>& charPrinter) const {
274 T copy = value;
275 if constexpr (std::is_signed<T>::value) {
276 if (copy < 0) {
277 charPrinter('-');
278 copy = -copy;
279 }
280 }
281 FixedPointInternals::printInt(copy, charPrinter, scale);
282 }
283
284 constexpr FixedPoint abs() const {
285 FixedPoint ret = *this;
286 if constexpr (std::is_signed<T>::value) {
287 if (ret.value < 0) {
288 ret.value = -ret.value;
289 }
290 }
291 return ret;
292 }
293
294 constexpr FixedPoint operator+(FixedPoint other) const {
295 FixedPoint ret = *this;
296 ret.value += other.value;
297 return ret;
298 }
299
300 template <std::integral U>
301 constexpr FixedPoint operator+(U other) const {
302 FixedPoint ret = *this;
303 ret.value += other * scale;
304 return ret;
305 }
306
307 constexpr FixedPoint operator-(FixedPoint other) const {
308 FixedPoint ret = *this;
309 ret.value -= other.value;
310 return ret;
311 }
312
313 template <std::integral U>
314 constexpr FixedPoint operator-(U other) const {
315 FixedPoint ret = *this;
316 ret.value -= other * scale;
317 return ret;
318 }
319
320 constexpr FixedPoint operator*(FixedPoint other) const {
321 upType t = value;
322 t *= other.value;
323 t /= scale;
324 FixedPoint ret;
325 ret.value = t;
326 return ret;
327 }
328
329 template <std::integral U>
330 constexpr FixedPoint operator*(U other) const {
331 FixedPoint ret = *this;
332 ret.value *= other;
333 return ret;
334 }
335
336 constexpr FixedPoint operator/(FixedPoint other) const {
337 FixedPoint ret;
338 if constexpr (sizeof(T) == 4) {
339 if constexpr (std::is_signed<T>::value) {
340 ret.value = FixedPointInternals::dDiv(value, other.value, scale);
341 } else if constexpr (!std::is_signed<T>::value) {
342 ret.value = FixedPointInternals::iDiv(value, other.value, scale);
343 }
344 } else if constexpr (sizeof(T) < 4) {
345 upType t = value;
346 t *= scale;
347 t /= other.value;
348 ret.value = t;
349 }
350 return ret;
351 }
352
353 template <std::integral U>
354 constexpr FixedPoint operator/(U other) const {
355 FixedPoint ret = *this;
356 ret.value /= other;
357 return ret;
358 }
359
360 constexpr FixedPoint operator-() const {
361 FixedPoint ret = *this;
362 ret.value = -ret.value;
363 return ret;
364 }
365
366 constexpr FixedPoint& operator+=(FixedPoint other) {
367 value += other.value;
368 return *this;
369 }
370
371 template <std::integral U>
372 constexpr FixedPoint& operator+=(U other) {
373 value += other * scale;
374 return *this;
375 }
376
377 constexpr FixedPoint& operator-=(FixedPoint other) {
378 value -= other.value;
379 return *this;
380 }
381
382 template <std::integral U>
383 constexpr FixedPoint& operator-=(U other) {
384 value -= other * scale;
385 return *this;
386 }
387
388 constexpr FixedPoint& operator*=(FixedPoint other) {
389 upType t = value;
390 t *= other.value;
391 t /= scale;
392 value = t;
393 return *this;
394 }
395
396 template <std::integral U>
397 constexpr FixedPoint& operator*=(U other) {
398 value *= other;
399 return *this;
400 }
401
402 constexpr FixedPoint& operator/=(FixedPoint other) {
403 if constexpr (sizeof(T) == 4) {
404 if constexpr (std::is_signed<T>::value) {
405 value = FixedPointInternals::dDiv(value, other.value, scale);
406 } else if constexpr (!std::is_signed<T>::value) {
407 value = FixedPointInternals::iDiv(value, other.value, scale);
408 }
409 } else if constexpr (sizeof(T) == 2) {
410 upType t = value;
411 t *= scale;
412 t /= other.value;
413 value = t;
414 }
415 return *this;
416 }
417
418 template <std::integral U>
419 constexpr FixedPoint& operator/=(U other) {
420 value /= other;
421 return *this;
422 }
423
424 auto operator<=>(const FixedPoint& other) const = default;
425
426 constexpr FixedPoint operator<<(unsigned shift) const {
427 FixedPoint ret = *this;
428 ret.value <<= shift;
429 return ret;
430 }
431
432 constexpr FixedPoint operator>>(unsigned shift) const {
433 FixedPoint ret = *this;
434 ret.value >>= shift;
435 return ret;
436 }
437
438 constexpr FixedPoint& operator<<=(unsigned shift) {
439 value <<= shift;
440 return *this;
441 }
442
443 constexpr FixedPoint& operator>>=(unsigned shift) {
444 value >>= shift;
445 return *this;
446 }
447
448 constexpr FixedPoint operator++() {
449 value += scale;
450 return *this;
451 }
452
453 constexpr FixedPoint operator++(int) {
454 FixedPoint ret = *this;
455 value += scale;
456 return ret;
457 }
458
459 constexpr FixedPoint operator--() {
460 value -= scale;
461 return *this;
462 }
463
464 constexpr FixedPoint operator--(int) {
465 FixedPoint ret = *this;
466 value -= scale;
467 return ret;
468 }
469
470 constexpr bool operator!() const { return value == 0; }
471};
472
473template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
474 std::integral U = int32_t>
475constexpr FixedPoint<precisionBits, T, scale> operator+(U a, FixedPoint<precisionBits, T, scale> b) {
476 return b + a;
477}
478
479template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
480 std::integral U = int32_t>
481constexpr FixedPoint<precisionBits, T, scale> operator-(U a, FixedPoint<precisionBits, T, scale> b) {
482 return -b + a;
483}
484
485template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
486 std::integral U = int32_t>
487constexpr FixedPoint<precisionBits, T, scale> operator*(U a, FixedPoint<precisionBits, T, scale> b) {
488 return b * a;
489}
490
491template <unsigned precisionBits = 12, std::integral T = int32_t, unsigned scale = 1 << precisionBits,
492 std::integral U = int32_t>
493constexpr FixedPoint<precisionBits, T, scale> operator/(U a, FixedPoint<precisionBits, T, scale> b) {
494 FixedPoint<precisionBits, T, scale> ret;
495 if constexpr (sizeof(T) == 4) {
496 if constexpr (std::is_signed<T>::value || std::is_signed<U>::value) {
497 ret.value = FixedPointInternals::dDiv(a * FixedPoint<precisionBits, T>::scale, b.raw(), scale);
498 } else if constexpr (!std::is_signed<T>::value && !std::is_signed<U>::value) {
499 ret.value = FixedPointInternals::iDiv(a * FixedPoint<precisionBits, T>::scale, b.raw(), scale);
500 }
501 } else if constexpr (sizeof(T) == 2) {
502 ret.value = a * FixedPoint<precisionBits, T>::scale / b.raw();
503 }
504 return ret;
505}
506
507namespace fixed_point_literals {
508
515consteval FixedPoint<> operator""_fp(long double value) { return value; }
516
517} // namespace fixed_point_literals
518
519} // namespace psyqo
uint32_t t
Definition cop0.c:79
uint8_t b
Definition gte-depthcue.c:39
constexpr uint32_t iDiv(uint64_t rem, uint32_t base, unsigned scale)
Definition fixed-point.hh:42
void printInt(uint32_t value, const eastl::function< void(char)> &, unsigned scale)
Definition fixed-point.cpp:30
constexpr int32_t dDiv(int32_t a, int32_t b, unsigned scale)
Definition fixed-point.hh:72
Definition lua.hh:38
psyqo::AdvancedPad::Pad & operator++(psyqo::AdvancedPad::Pad &pad)
Definition advancedpad.hh:255
psyqo::AdvancedPad::Pad & operator--(psyqo::AdvancedPad::Pad &pad)
Definition advancedpad.hh:267
char * s
Definition string.c:48
static int value
Definition syscalls.h:535
static int ret
Definition syscalls.h:73
void uint32_t(classId, spec)