#pragma once #include #include #include "div.hpp" struct fp_raw_tag {}; template constexpr inline int fp_fractional(std::floating_point auto n) { return (n - static_cast(n)) * (1 << B); } template constexpr inline int fp_integral(std::floating_point auto n) { return static_cast(n) << B; } template struct fp { T value; constexpr inline fp(std::integral auto n) : value(n * (1 << B)) {} consteval inline fp(std::floating_point auto n) : value(fp_integral(n) + fp_fractional(n)) {} constexpr inline explicit fp(T n, struct fp_raw_tag) : value(n) {} constexpr inline explicit operator int() const { return value >> 16; } constexpr inline fp operator-() const { return fp(-value, fp_raw_tag{}); } inline constexpr fp& operator=(fp const& v); inline constexpr fp& operator+=(fp const& v); inline constexpr fp& operator-=(fp const& v); inline constexpr fp& operator*=(fp const& v); }; template inline constexpr fp& fp::operator=(fp const& v) { this->value = v.value; return *this; } template inline constexpr fp& fp::operator+=(fp const& v) { *this = *this + v; return *this; } template inline constexpr fp& fp::operator-=(fp const& v) { *this = *this - v; return *this; } template inline constexpr fp& fp::operator*=(fp const& v) { *this = *this * v; return *this; } template constexpr inline fp operator+(const fp& a, const fp& b) { return fp(a.value + b.value, fp_raw_tag{}); } template constexpr inline fp operator>>(const fp& a, int s) { return fp(a.value >> s, fp_raw_tag{}); } template constexpr inline fp operator<<(const fp& a, int s) { return fp(a.value << s, fp_raw_tag{}); } template constexpr inline fp operator-(const fp& a, const fp& b) { return fp(a.value - b.value, fp_raw_tag{}); } template constexpr inline fp operator*(const fp& a, const fp& b) { const I p = (static_cast(a.value) * static_cast(b.value)); return fp(static_cast(p >> B), fp_raw_tag{}); } template constexpr inline fp operator*(const fp& a, T b) { I p = (static_cast(a.value) * static_cast(b)); return fp(static_cast(p), fp_raw_tag{}); } template constexpr inline fp operator*(T b, const fp& a) { I p = (static_cast(a.value) * static_cast(b)); return fp(static_cast(p), fp_raw_tag{}); } template constexpr inline fp operator/(const fp& a, const fp& b) { //T p = (static_cast(a.value) * ) / static_cast(b.value); //T p = static_cast(a.value) / static_cast(b.value); I p = __div64_32((static_cast(a.value) << 16), static_cast(b.value)); return fp(static_cast(p), fp_raw_tag{}); } // comparison template constexpr inline bool operator==(const fp& a, const fp& b) { return a.value == b.value; } template constexpr inline bool operator!=(const fp& a, const fp& b) { return a.value != b.value; } template constexpr inline bool operator<(const fp& a, const fp& b) { return a.value < b.value; } template constexpr inline bool operator>(const fp& a, const fp& b) { return a.value > b.value; } template constexpr inline bool operator<=(const fp& a, const fp& b) { return a.value <= b.value; } template constexpr inline bool operator>=(const fp& a, const fp& b) { return a.value >= b.value; } // limits template struct fp_limits; template struct fp_limits> { static constexpr fp min() { return fp(-(1 << (2 * B - 1)), fp_raw_tag{}); } static constexpr fp max() { return fp((static_cast(1) << (2 * B - 1)) - 1, fp_raw_tag{}); } }; // functions template constexpr inline fp pow(fp a, fp b) { while (b > fp(1)) { a *= a; b -= fp(1); } return a; } // specializations using fp16_16 = fp; constexpr inline fp16_16 sqrt(const fp16_16& n) { int32_t x = n.value; int32_t c = 0; int32_t d = 1 << 30; while (d > (1 << 6)) { int32_t t = c + d; if (x >= t) { x -= t; c = t + d; } x <<= 1; d >>= 1; } return fp16_16(c >> 8, fp_raw_tag{}); }