#pragma once #include template class fixed { protected: T _value; constexpr fixed(T rawValue, int dummy) : _value(rawValue) { } public: constexpr fixed() { } template constexpr fixed(fixed value) : _value(value.GetRawValue()) { } template explicit constexpr fixed(fixed value) { if (FractionBits == OtherFractionBits) _value = value.GetRawValue(); else if (OtherFractionBits < FractionBits) _value = value.GetRawValue() << (FractionBits - OtherFractionBits); else { const T2 rounding = (T2)(1ULL << ((OtherFractionBits - FractionBits) - 1)); const int shift = OtherFractionBits - FractionBits; _value = (value.GetRawValue() + rounding) >> shift; } } constexpr fixed(int value) : _value(value << FractionBits) { } constexpr fixed(s64 value) : _value(value << FractionBits) { } constexpr fixed(float value) : _value(std::round(value * (1 << FractionBits))) { } constexpr fixed(double value) : _value(std::round(value * (1 << FractionBits))) { } constexpr fixed(long double value) : _value(std::round(value * (1 << FractionBits))) { } constexpr T Int() const { return _value >> FractionBits; } constexpr T GetRawValue() const { return _value; } }; template class fix32; template class fix64; template class fix16 : public fixed { constexpr fix16(s16 rawValue, int dummy) : fixed(rawValue, dummy) { } public: constexpr fix16() { } constexpr fix16(const fix16& value) : fixed(value) { } template explicit constexpr fix16(const fixed& value) : fixed(value) { } constexpr fix16(s16 value) : fixed(value) { } constexpr fix16(int value) : fixed(value) { } constexpr fix16(float value) : fixed(value) { } constexpr fix16(double value) : fixed(value) { } constexpr fix16(long double value) : fixed(value) { } constexpr bool operator<(const fix16& other) const { return this->_value < other._value; } constexpr bool operator<=(const fix16& other) const { return this->_value <= other._value; } constexpr bool operator>(const fix16& other) const { return this->_value > other._value; } constexpr bool operator>=(const fix16& other) const { return this->_value >= other._value; } constexpr fix16 operator-() const { return FromRawValue(-this->_value); } constexpr fix16 operator+(const fix16& other) const { return FromRawValue(this->_value + other._value); } template constexpr fix16 operator+(TOther other) const { return FromRawValue(this->_value + fix16(other)._value); } template constexpr friend fix16 operator+(TLhs lhs, const fix16& rhs) { return FromRawValue(fix16(lhs)._value + rhs._value); } constexpr fix16 operator-(const fix16& other) const { return FromRawValue(this->_value - other._value); } template constexpr fix16 operator-(TOther other) const { return FromRawValue(this->_value - fix16(other)._value); } template constexpr friend fix16 operator-(TLhs lhs, fix16 rhs) { return FromRawValue(fix16(lhs)._value - rhs._value); } constexpr fix16 operator<<(int rhs) const { return FromRawValue(this->_value << rhs); } constexpr fix16 operator>>(int rhs) const { return FromRawValue(this->_value >> rhs); } constexpr fix16 Abs() const { return FromRawValue(std::abs(this->_value)); } constexpr fix16 Clamp(fix16 min, fix16 max) const { if (this->_value < min._value) { return min; } else if (this->_value > max._value) { return max; } else { return *this; } } template constexpr fix32 LongMul(const fix16& other) const { return fix32::FromRawValue(this->_value * other.GetRawValue()); } template constexpr fix64 LongMul(const fix32& other) const { return fix64::FromRawValue(this->_value * (s64)other._value); } template constexpr fix16 operator*(const fix16& other) const { return fix16(LongMul(other)); } template constexpr fix16 operator*(const fix32& other) const { return fix16(LongMul(other)); } constexpr fix16 operator*(s16 other) const { return FromRawValue(this->_value * other); } constexpr friend fix16 operator*(s16 lhs, const fix16& rhs) { return FromRawValue(lhs * rhs.GetRawValue()); } template constexpr fix16 operator/(const fix16& other) const { s32 lhs = (s32)this->_value << 16; s32 rhs = other.GetRawValue(); s32 divResult; if (std::is_constant_evaluated()) divResult = lhs / rhs; else divResult = math_div32(lhs, rhs); return fix16(fix32::FromRawValue(divResult)); } static constexpr fix16 FromRawValue(s16 value) { return fix16(value, 0); } }; template class fix32 : public fixed { constexpr fix32(int rawValue, int dummy) : fixed(rawValue, dummy) { } public: constexpr fix32() { } constexpr fix32(const fix16& value) : fixed(value) { } constexpr fix32(const fix32& value) : fixed(value) { } template explicit constexpr fix32(const fixed& value) : fixed(value) { } constexpr fix32(int value) : fixed(value) { } constexpr fix32(float value) : fixed(value) { } constexpr fix32(double value) : fixed(value) { } constexpr fix32(long double value) : fixed(value) { } constexpr bool operator==(const fix32& other) const { return this->_value == other._value; } constexpr bool operator!=(const fix32& other) const { return this->_value != other._value; } constexpr bool operator<(const fix32& other) const { return this->_value < other._value; } template constexpr friend bool operator<(TLhs lhs, const fix32& rhs) { return fix32(lhs)._value < rhs._value; } constexpr bool operator<=(const fix32& other) const { return this->_value <= other._value; } template constexpr friend bool operator<=(TLhs lhs, const fix32& rhs) { return fix32(lhs)._value <= rhs._value; } constexpr bool operator>(const fix32& other) const { return this->_value > other._value; } template constexpr friend bool operator>(TLhs lhs, const fix32& rhs) { return fix32(lhs)._value > rhs._value; } constexpr bool operator>=(const fix32& other) const { return this->_value >= other._value; } template constexpr friend bool operator>=(TLhs lhs, const fix32& rhs) { return fix32(lhs)._value >= rhs._value; } constexpr fix32 operator-() const { return FromRawValue(-this->_value); } constexpr fix32 operator+(const fix32& other) const { return FromRawValue(this->_value + other._value); } template constexpr fix32 operator+(TOther other) const { return FromRawValue(this->_value + fix32(other)._value); } template constexpr friend fix32 operator+(TLhs lhs, const fix32& rhs) { return FromRawValue(fix32(lhs)._value + rhs._value); } constexpr fix32 operator-(const fix32& other) const { return FromRawValue(this->_value - other._value); } constexpr fix32 operator-(int other) const { return FromRawValue(this->_value - fix32(other)._value); } constexpr friend fix32 operator-(int lhs, const fix32& rhs) { return FromRawValue(fix32(lhs)._value - rhs._value); } constexpr fix32 operator/(int other) const { return FromRawValue(this->_value / other); } constexpr fix32 operator<<(int rhs) const { return FromRawValue(this->_value << rhs); } constexpr fix32 operator>>(int rhs) const { return FromRawValue(this->_value >> rhs); } constexpr fix32 Abs() const { return FromRawValue(std::abs(this->_value)); } constexpr fix32 Clamp(fix32 min, fix32 max) const { if (this->_value < min._value) { return min; } else if (this->_value > max._value) { return max; } else { return *this; } } template constexpr fix64 LongMul(const fix16& other) const { return fix64::FromRawValue((s64)this->_value * other.GetRawValue()); } template constexpr fix64 LongMul(const fix32& other) const { return fix64::FromRawValue((s64)this->_value * other.GetRawValue()); } constexpr fix64 LongMul(int other) const { return fix64::FromRawValue((s64)this->_value * other); } constexpr fix64 LongMul(double other) const { return LongMul(fix32(other)); } template constexpr fix32 operator*(const fix16& other) const { return fix32(LongMul(other)); } template constexpr fix32 operator*(const fix32& other) const { return fix32(LongMul(other)); } constexpr fix32 operator*(int other) const { return FromRawValue(this->_value * other); } constexpr fix32 operator*(double other) const { return fix32(LongMul(fix32(other))); } constexpr friend fix32 operator*(int lhs, const fix32& rhs) { return FromRawValue(lhs * rhs.GetRawValue()); } template constexpr fix32 operator/(const fix16& other) const { s64 lhs = (s64)this->_value << 32; s32 rhs = other.GetRawValue(); s64 divResult; if (std::is_constant_evaluated()) divResult = lhs / rhs; else divResult = math_div6432(lhs, rhs); return fix32(fix64::FromRawValue(divResult)); } template constexpr fix32 operator/(const fix32& other) const { s64 lhs = (s64)this->_value << 32; s32 rhs = other.GetRawValue(); s64 divResult; if (std::is_constant_evaluated()) divResult = lhs / rhs; else divResult = math_div6432(lhs, rhs); return fix32(fix64::FromRawValue(divResult)); } static constexpr fix32 FromRawValue(int value) { return fix32(value, 0); } }; // static constexpr fix32<12> operator""fx(long double value) { return fix32<12>(value); } template class fix64 : public fixed { constexpr fix64(s64 rawValue, int dummy) : fixed(rawValue, dummy) { } public: constexpr fix64() { } template constexpr fix64(const fixed& value) : fixed(value) { } template explicit constexpr fix64(const fixed& value) : fixed(value) { } constexpr fix64(int value) : fixed(value) { } constexpr fix64(s64 value) : fixed(value) { } constexpr fix64(float value) : fixed(value) { } constexpr fix64(double value) : fixed(value) { } constexpr fix64(long double value) : fixed(value) { } constexpr bool operator<(const fix64& other) const { return this->_value < other._value; } constexpr bool operator<=(const fix64& other) const { return this->_value <= other._value; } constexpr bool operator>(const fix64& other) const { return this->_value > other._value; } constexpr bool operator>=(const fix64& other) const { return this->_value >= other._value; } constexpr fix64 operator+(const fix64& other) const { return FromRawValue(this->_value + other._value); } constexpr fix64 operator-(const fix64& other) const { return FromRawValue(this->_value - other._value); } static constexpr fix64 FromRawValue(s64 value) { return fix64(value, 0); } };