#ifndef FIXED_POINT_NUMBER_HPP #define FIXED_POINT_NUMBER_HPP #include #include #include #include #include #include namespace osrm { // implements an binary based fixed point number type template class FixedPointNumber { static_assert(FractionalBitSize > 0, "FractionalBitSize must be greater than 0"); static_assert(FractionalBitSize <= 32, "FractionalBitSize must at most 32"); typename std::conditional::type m_fixed_point_state; constexpr static const decltype(m_fixed_point_state) PRECISION = 1 << FractionalBitSize; // state signage encapsulates whether the state should either represent a // signed or an unsigned floating point number using state_signage = typename std::conditional::type, decltype(m_fixed_point_state)>::type; public: FixedPointNumber() : m_fixed_point_state(0) {} // the type is either initialized with a floating point value or an // integral state. Anything else will throw at compile-time. template constexpr FixedPointNumber(const T &&input) noexcept : m_fixed_point_state(static_cast( std::round(std::forward(input) * PRECISION))) { static_assert( std::is_floating_point::value || std::is_integral::value, "FixedPointNumber needs to be initialized with floating point or integral value"); } // get max value template ::value>::type * = nullptr> constexpr static auto max() noexcept -> T { return static_cast(std::numeric_limits::max()) / PRECISION; } // get min value template ::value>::type * = nullptr> constexpr static auto min() noexcept -> T { return static_cast(1) / PRECISION; } // get lowest value template ::value>::type * = nullptr> constexpr static auto lowest() noexcept -> T { return static_cast(std::numeric_limits::min()) / PRECISION; } // cast to floating point type T, return value template ::value>::type * = nullptr> explicit operator const T() const noexcept { // casts to external type (signed or unsigned) and then to float return static_cast(static_cast(m_fixed_point_state)) / PRECISION; } // warn about cast to integral type T, its disabled for good reason template ::value>::type * = nullptr> explicit operator T() const { static_assert(std::is_integral::value, "casts to integral types have been disabled on purpose"); } // compare, ie. sort fixed-point numbers bool operator<(const FixedPointNumber &other) const noexcept { return m_fixed_point_state < other.m_fixed_point_state; } // equality, ie. sort fixed-point numbers bool operator==(const FixedPointNumber &other) const noexcept { return m_fixed_point_state == other.m_fixed_point_state; } bool operator!=(const FixedPointNumber &other) const { return !(*this == other); } bool operator>(const FixedPointNumber &other) const { return other < *this; } bool operator<=(const FixedPointNumber &other) const { return !(other < *this); } bool operator>=(const FixedPointNumber &other) const { return !(*this < other); } // arithmetic operators FixedPointNumber operator+(const FixedPointNumber &other) const noexcept { FixedPointNumber tmp = *this; tmp.m_fixed_point_state += other.m_fixed_point_state; return tmp; } FixedPointNumber &operator+=(const FixedPointNumber &other) noexcept { this->m_fixed_point_state += other.m_fixed_point_state; return *this; } FixedPointNumber operator-(const FixedPointNumber &other) const noexcept { FixedPointNumber tmp = *this; tmp.m_fixed_point_state -= other.m_fixed_point_state; return tmp; } FixedPointNumber &operator-=(const FixedPointNumber &other) noexcept { this->m_fixed_point_state -= other.m_fixed_point_state; return *this; } FixedPointNumber operator*(const FixedPointNumber &other) const noexcept { int64_t temp = this->m_fixed_point_state; temp *= other.m_fixed_point_state; // rounding! if (!truncate_results) { temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1); } temp >>= FractionalBitSize; FixedPointNumber tmp; tmp.m_fixed_point_state = static_cast(temp); return tmp; } FixedPointNumber &operator*=(const FixedPointNumber &other) noexcept { int64_t temp = this->m_fixed_point_state; temp *= other.m_fixed_point_state; // rounding! if (!truncate_results) { temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1); } temp >>= FractionalBitSize; this->m_fixed_point_state = static_cast(temp); return *this; } FixedPointNumber operator/(const FixedPointNumber &other) const noexcept { int64_t temp = this->m_fixed_point_state; temp <<= FractionalBitSize; temp /= static_cast(other.m_fixed_point_state); FixedPointNumber tmp; tmp.m_fixed_point_state = static_cast(temp); return tmp; } FixedPointNumber &operator/=(const FixedPointNumber &other) noexcept { int64_t temp = this->m_fixed_point_state; temp <<= FractionalBitSize; temp /= static_cast(other.m_fixed_point_state); FixedPointNumber tmp; this->m_fixed_point_state = static_cast(temp); return *this; } }; static_assert(4 == sizeof(FixedPointNumber<1>), "FP19 has wrong size != 4"); } #endif // FIXED_POINT_NUMBER_HPP