#pragma once #include struct fp_raw_tag {}; template struct fp { T value; constexpr inline fp(T n) noexcept : value(n * (1 << B)) {} constexpr inline explicit fp(T n, struct fp_raw_tag) noexcept : value(n) {} constexpr inline fp operator-() const noexcept { return fp(-value, fp_raw_tag{}); } }; template constexpr inline fp operator+(const fp& a, const fp& b) noexcept { return fp(a.value + b.value, fp_raw_tag{}); } template constexpr inline fp operator-(const fp& a, const fp& b) noexcept { return fp(a.value - b.value, fp_raw_tag{}); } template constexpr inline fp operator*(const fp& a, const fp& b) noexcept { 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) noexcept { 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) noexcept { 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) noexcept { I p = (static_cast(a.value) * (static_cast(1) << B)) / static_cast(b.value); return fp(static_cast(p), fp_raw_tag{}); } // comparison template constexpr inline bool operator==(const fp& a, const fp& b) noexcept { return a.value == b.value; } template constexpr inline bool operator!=(const fp& a, const fp& b) noexcept { return a.value != b.value; } template constexpr inline bool operator<(const fp& a, const fp& b) noexcept { return a.value < b.value; } template constexpr inline bool operator>(const fp& a, const fp& b) noexcept { return a.value > b.value; } template constexpr inline bool operator<=(const fp& a, const fp& b) noexcept { return a.value <= b.value; } template constexpr inline bool operator>=(const fp& a, const fp& b) noexcept { return a.value >= b.value; } // limits template struct fp_limits; template struct fp_limits> { static constexpr fp min() noexcept { return fp(-(1 << (2 * B - 1)), fp_raw_tag{}); } static constexpr fp max() noexcept { return fp((static_cast(1) << (2 * B - 1)) - 1, fp_raw_tag{}); } }; // specializations using fp16_16 = fp; constexpr fp16_16 sqrt(fp16_16 n) noexcept { 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{}); }