#pragma once #include #include #include template class Fixed { private: template struct Cast { private: template struct Tag {}; inline static T Convert(T2 value, Tag) { return static_cast(value) << (F - F2); } inline static T Convert(T2 value, Tag) { return static_cast(value) >> (F2 - F); } inline static T Convert(T2 value, Tag) { return static_cast(value << (F - F2)); } inline static T Convert(T2 value, Tag) { return static_cast(value >> (F2 - F)); } public: inline static T Convert(T2 value) { return Convert(value, Tag<(sizeof(T2) > sizeof(T)), (F2 > F)>{}); } }; public: using data_type = T; static constexpr uint32_t FRAC = F; static constexpr uint32_t INT = sizeof(T) * 8 - FRAC; static constexpr uint32_t HFRAC = FRAC >> 1; static constexpr T ONE = static_cast(1) << FRAC; static constexpr T MASK = ONE - 1; static constexpr T IMASK = ~MASK; static constexpr T HALF = ONE >> 1; static constexpr T TWO = ONE << 1; Fixed() {} explicit Fixed(int64_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } explicit Fixed(uint64_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } explicit Fixed(int32_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } explicit Fixed(uint32_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } explicit Fixed(int16_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } explicit Fixed(uint16_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } explicit Fixed(int8_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } explicit Fixed(uint8_t rhs) : data_(static_cast(rhs << FRAC)) { assert((static_cast(rhs) << FRAC) == data_); } template explicit Fixed(Fixed rhs) : data_(Cast::Convert(rhs.data())) {} explicit Fixed(float rhs) : data_(static_cast(rhs * ONE)) { assert(data_ == static_cast(rhs * ONE)); } bool operator==(Fixed rhs) const { return (data_ == rhs.data_); } bool operator!=(Fixed rhs) const { return (data_ != rhs.data_); } bool operator<(Fixed rhs) const { return (data_ < rhs.data_); } bool operator<=(Fixed rhs) const { return (data_ <= rhs.data_); } bool operator>(Fixed rhs) const { return (data_ > rhs.data_); } bool operator>=(Fixed rhs) const { return (data_ >= rhs.data_); } Fixed operator-() const { return make(-data_); } Fixed operator+=(Fixed rhs) { *this = (*this) + rhs; return *this; } Fixed operator-=(Fixed rhs) { *this = (*this) - rhs; return *this; } Fixed operator*=(Fixed rhs) { *this = (*this) * rhs; return *this; } Fixed operator/=(Fixed rhs) { *this = (*this) / rhs; return *this; } template Fixed operator*=(Fixed rhs) { *this = (*this) * rhs; return *this; } template Fixed operator/=(Fixed rhs) { *this = (*this) / rhs; return *this; } Fixed operator*=(int32_t rhs) { *this = (*this) * rhs; return *this; } Fixed operator*=(uint32_t rhs) { *this = (*this) * rhs; return *this; } Fixed operator*=(float rhs) { *this = (*this) * rhs; return *this; } Fixed operator/=(int32_t rhs) { *this = (*this) / rhs; return *this; } Fixed operator/=(uint32_t rhs) { *this = (*this) / rhs; return *this; } Fixed operator/=(float rhs) { *this = (*this) / rhs; return *this; } friend Fixed operator+(Fixed lhs, Fixed rhs) { assert((static_cast(lhs.data_) + rhs.data_) == (lhs.data_ + rhs.data_)); return Fixed::make(lhs.data_ + rhs.data_); } friend Fixed operator-(Fixed lhs, Fixed rhs) { assert((static_cast(lhs.data_) - rhs.data_) == (lhs.data_ - rhs.data_)); return Fixed::make(lhs.data_ - rhs.data_); } friend Fixed operator*(Fixed lhs, Fixed rhs) { return Fixed::make((static_cast(lhs.data_) * rhs.data_) >> FRAC); } template friend Fixed operator*(Fixed lhs, Fixed rhs) { return Fixed::make((static_cast(lhs.data_) * rhs.data()) >> F2); } friend Fixed operator/(Fixed lhs, Fixed rhs) { assert(rhs.data_ != 0); return Fixed::make((static_cast(lhs.data_) << FRAC) / rhs.data_); } template friend Fixed operator/(Fixed lhs, Fixed rhs) { assert(rhs.data() != 0); return Fixed::make((static_cast(lhs.data_) << F2) / rhs.data()); } friend Fixed operator*(Fixed lhs, float rhs) { return static_cast(lhs) * rhs; } friend Fixed operator*(float lhs, Fixed rhs) { return lhs * static_cast(rhs); } friend Fixed operator/(Fixed lhs, float rhs) { return static_cast(lhs) / rhs; } friend Fixed operator/(float lhs, Fixed rhs) { return lhs / static_cast(rhs); } friend Fixed operator*(Fixed lhs, char rhs) { return lhs * static_cast(rhs); } friend Fixed operator*(char lhs, Fixed rhs) { return rhs * lhs; } friend Fixed operator/(Fixed lhs, char rhs) { return lhs / static_cast(rhs); } friend Fixed operator/(char lhs, Fixed rhs) { return rhs / lhs; } friend Fixed operator*(Fixed lhs, uint8_t rhs) { return lhs * static_cast(rhs); } friend Fixed operator*(uint8_t lhs, Fixed rhs) { return rhs * lhs; } friend Fixed operator/(Fixed lhs, uint8_t rhs) { return lhs / static_cast(rhs); } friend Fixed operator/(uint8_t lhs, Fixed rhs) { return rhs / lhs; } friend Fixed operator*(Fixed lhs, short rhs) { return lhs * static_cast(rhs); } friend Fixed operator*(short lhs, Fixed rhs) { return rhs * lhs; } friend Fixed operator/(Fixed lhs, short rhs) { return lhs / static_cast(rhs); } friend Fixed operator/(short lhs, Fixed rhs) { return rhs / lhs; } friend Fixed operator*(Fixed lhs, uint16_t rhs) { return lhs * static_cast(rhs); } friend Fixed operator*(uint16_t lhs, Fixed rhs) { return rhs * lhs; } friend Fixed operator/(Fixed lhs, uint16_t rhs) { return lhs / static_cast(rhs); } friend Fixed operator/(uint16_t lhs, Fixed rhs) { return rhs / lhs; } friend Fixed operator*(Fixed lhs, int32_t rhs) { auto value = static_cast(lhs.data_ * rhs); assert((lhs.data_ * static_cast(rhs)) == value); return Fixed::make(value); } friend Fixed operator*(int32_t lhs, Fixed rhs) { return rhs * lhs; } friend Fixed operator/(Fixed lhs, int32_t rhs) { assert(rhs); auto value = static_cast(lhs.data_ / rhs); return Fixed::make(value); } friend Fixed operator/(int32_t lhs, Fixed rhs) { return rhs / lhs; } friend Fixed operator*(Fixed lhs, uint32_t rhs) { auto value = static_cast(lhs.data_ << rhs); assert((lhs.data_ << static_cast(rhs)) == value); return Fixed::make(value); } friend Fixed operator*(uint32_t lhs, Fixed rhs) { return rhs * lhs; } friend Fixed operator/(Fixed lhs, uint32_t rhs) { assert(rhs); auto value = static_cast(lhs.data_ / rhs); return Fixed::make(value); } friend Fixed operator/(uint32_t lhs, Fixed rhs) { return rhs / lhs; } friend Fixed operator<<(Fixed lhs, int32_t rhs) { auto value = static_cast(lhs.data_ << rhs); assert((lhs.data_ << static_cast(rhs)) == value); return Fixed::make(value); } friend Fixed operator>>(Fixed lhs, int32_t rhs) { auto value = static_cast(lhs.data_ >> rhs); return Fixed::make(value); } friend Fixed operator<<(Fixed lhs, uint32_t rhs) { auto value = static_cast(lhs.data_ << rhs); assert((lhs.data_ << static_cast(rhs)) == value); return Fixed::make(value); } friend Fixed operator>>(Fixed lhs, uint32_t rhs) { auto value = static_cast(lhs.data_ >> rhs); return Fixed::make(value); } static Fixed make(T value) { Fixed ret; ret.data_ = value; return ret; } explicit operator int64_t() const { return static_cast(data_ >> F); } explicit operator uint64_t() const { return static_cast(data_ >> F); } explicit operator int32_t() const { return static_cast(data_ >> F); } explicit operator uint32_t() const { return static_cast(data_ >> F); } explicit operator int16_t() const { return static_cast(data_ >> F); } explicit operator uint16_t() const { return static_cast(data_ >> F); } explicit operator int8_t() const { return static_cast(data_ >> F); } explicit operator uint8_t() const { return static_cast(data_ >> F); } template explicit operator Fixed() const { return Fixed(*this); } explicit operator float() const { return static_cast(data_) / (static_cast(1) << F); } T data() const { return data_; } private: T data_; };