|
|
|
#ifndef FIXED_H_
|
|
#define FIXED_H_
|
|
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <type_traits>
|
|
|
|
template <typename IntegerType, typename FractionalType>
|
|
class fixed
|
|
{
|
|
static_assert(std::is_integral<IntegerType>::value, "IntegerType must be an integral type");
|
|
static_assert(std::is_integral<FractionalType>::value, "FractionalType must be an integral type");
|
|
|
|
static_assert(std::is_signed<IntegerType>::value, "IntegerType must be a signed type");
|
|
static_assert(std::is_unsigned<FractionalType>::value, "FractionalType must be an unsigned type");
|
|
|
|
public:
|
|
|
|
static constexpr size_t integer_bits = sizeof(IntegerType) * 8;
|
|
static constexpr size_t fractional_bits = sizeof(FractionalType) * 8;
|
|
|
|
static constexpr size_t integer_decimal_digits = std::floor(std::log10(std::numeric_limits<IntegerType>::max()));
|
|
static constexpr size_t fractional_decimal_digits = std::floor(std::log10(std::numeric_limits<FractionalType>::max()));
|
|
|
|
static constexpr size_t MAX_INTEGER_VALUE = (static_cast<uint64_t>(std::pow(10, integer_decimal_digits)) - 1);
|
|
static constexpr size_t MIN_INTEGER_VALUE = 0;
|
|
|
|
static constexpr size_t MAX_FRACTIONAL_VALUE = (static_cast<uint64_t>(std::pow(10, fractional_decimal_digits)) - 1);
|
|
static constexpr size_t MIN_FRACTIONAL_VALUE = 0;
|
|
|
|
fixed()
|
|
: m_integer(0), m_fractional(0) {}
|
|
|
|
fixed(IntegerType integerVal, FractionalType fractionalVal)
|
|
: m_integer(integerVal), m_fractional(fractionalVal) {}
|
|
|
|
// Default copy constructor, and assignment operator
|
|
fixed(const fixed&) = default;
|
|
fixed& operator=(const fixed&) = default;
|
|
|
|
void parse(const char* input)
|
|
{
|
|
|
|
}
|
|
|
|
constexpr inline fixed operator-() const noexcept = delete;
|
|
inline fixed& operator+=(const fixed& y) noexcept = delete;
|
|
inline fixed& operator-=(const fixed& y) noexcept = delete;
|
|
inline fixed& operator*=(const fixed& y) noexcept = delete;
|
|
inline fixed& operator/=(const fixed& y) noexcept = delete;
|
|
|
|
// Comparison operators
|
|
template <typename I, typename F>
|
|
friend constexpr inline bool operator==(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
|
|
|
|
template <typename I, typename F>
|
|
friend constexpr inline bool operator!=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
|
|
|
|
template <typename I, typename F>
|
|
friend constexpr inline bool operator<(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
|
|
|
|
template <typename I, typename F>
|
|
friend constexpr inline bool operator>(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
|
|
|
|
template <typename I, typename F>
|
|
friend constexpr inline bool operator<=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
|
|
|
|
template <typename I, typename F>
|
|
friend constexpr inline bool operator>=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept;
|
|
|
|
private:
|
|
|
|
IntegerType m_integer;
|
|
FractionalType m_fractional;
|
|
|
|
};
|
|
|
|
using fixed_64_64 = fixed<int64_t, uint64_t>;
|
|
|
|
template <typename I, typename F>
|
|
constexpr inline bool operator==(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
|
|
{
|
|
return (x.m_integer == y.m_integer && x.m_fractional == y.m_fractional);
|
|
}
|
|
|
|
template <typename I, typename F>
|
|
constexpr inline bool operator!=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
|
|
{
|
|
return (! x == y);
|
|
}
|
|
|
|
template <typename I, typename F>
|
|
constexpr inline bool operator<(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
|
|
{
|
|
if (x.m_integer == y.m_integer)
|
|
{
|
|
return (x.m_fractional < y.m_fractional);
|
|
}
|
|
else
|
|
{
|
|
return (x.m_integer < y.m_integer);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template <typename I, typename F>
|
|
constexpr inline bool operator>(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
|
|
{
|
|
if (x.m_integer == y.m_integer)
|
|
{
|
|
return (x.m_fractional > y.m_fractional);
|
|
}
|
|
else
|
|
{
|
|
return (x.m_integer > y.m_integer);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template <typename I, typename F>
|
|
constexpr inline bool operator<=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
|
|
{
|
|
if (x.m_integer == y.m_integer)
|
|
{
|
|
return (x.m_fractional <= y.m_fractional);
|
|
}
|
|
else
|
|
{
|
|
return (x.m_integer < y.m_integer);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template <typename I, typename F>
|
|
constexpr inline bool operator>=(const fixed<I, F>& x, const fixed<I, F>& y) noexcept
|
|
{
|
|
if (x.m_integer == y.m_integer)
|
|
{
|
|
return (x.m_fractional > y.m_fractional);
|
|
}
|
|
else
|
|
{
|
|
return (x.m_integer > y.m_integer);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Addition
|
|
template <typename I, typename F>
|
|
constexpr inline fixed<I, F> operator+(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
|
|
|
|
// Subtraction
|
|
template <typename I, typename F>
|
|
constexpr inline fixed<I, F> operator-(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
|
|
|
|
// Multiplication
|
|
template <typename I, typename F>
|
|
constexpr inline fixed<I, F> operator*(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
|
|
|
|
// Division
|
|
template <typename I, typename F>
|
|
constexpr inline fixed<I, F> operator/(const fixed<I, F>& x, const fixed<I, F>& y) noexcept = delete;
|
|
|
|
|
|
#endif // FIXED_H_
|