Merge pull request #9094 from lioncash/fixed
common/fixed_point: Minor interface improvements
This commit is contained in:
commit
7daf751b8d
2 changed files with 80 additions and 115 deletions
|
@ -34,4 +34,12 @@ concept DerivedFrom = requires {
|
||||||
template <typename From, typename To>
|
template <typename From, typename To>
|
||||||
concept ConvertibleTo = std::is_convertible_v<From, To>;
|
concept ConvertibleTo = std::is_convertible_v<From, To>;
|
||||||
|
|
||||||
|
// No equivalents in the stdlib
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept IsArithmetic = std::is_arithmetic_v<T>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept IsIntegral = std::is_integral_v<T>;
|
||||||
|
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <common/concepts.h>
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
template <size_t I, size_t F>
|
template <size_t I, size_t F>
|
||||||
|
@ -50,8 +52,8 @@ struct type_from_size<64> {
|
||||||
static constexpr size_t size = 64;
|
static constexpr size_t size = 64;
|
||||||
|
|
||||||
using value_type = int64_t;
|
using value_type = int64_t;
|
||||||
using unsigned_type = std::make_unsigned<value_type>::type;
|
using unsigned_type = std::make_unsigned_t<value_type>;
|
||||||
using signed_type = std::make_signed<value_type>::type;
|
using signed_type = std::make_signed_t<value_type>;
|
||||||
using next_size = type_from_size<128>;
|
using next_size = type_from_size<128>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,8 +63,8 @@ struct type_from_size<32> {
|
||||||
static constexpr size_t size = 32;
|
static constexpr size_t size = 32;
|
||||||
|
|
||||||
using value_type = int32_t;
|
using value_type = int32_t;
|
||||||
using unsigned_type = std::make_unsigned<value_type>::type;
|
using unsigned_type = std::make_unsigned_t<value_type>;
|
||||||
using signed_type = std::make_signed<value_type>::type;
|
using signed_type = std::make_signed_t<value_type>;
|
||||||
using next_size = type_from_size<64>;
|
using next_size = type_from_size<64>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,8 +74,8 @@ struct type_from_size<16> {
|
||||||
static constexpr size_t size = 16;
|
static constexpr size_t size = 16;
|
||||||
|
|
||||||
using value_type = int16_t;
|
using value_type = int16_t;
|
||||||
using unsigned_type = std::make_unsigned<value_type>::type;
|
using unsigned_type = std::make_unsigned_t<value_type>;
|
||||||
using signed_type = std::make_signed<value_type>::type;
|
using signed_type = std::make_signed_t<value_type>;
|
||||||
using next_size = type_from_size<32>;
|
using next_size = type_from_size<32>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,8 +85,8 @@ struct type_from_size<8> {
|
||||||
static constexpr size_t size = 8;
|
static constexpr size_t size = 8;
|
||||||
|
|
||||||
using value_type = int8_t;
|
using value_type = int8_t;
|
||||||
using unsigned_type = std::make_unsigned<value_type>::type;
|
using unsigned_type = std::make_unsigned_t<value_type>;
|
||||||
using signed_type = std::make_signed<value_type>::type;
|
using signed_type = std::make_signed_t<value_type>;
|
||||||
using next_size = type_from_size<16>;
|
using next_size = type_from_size<16>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +103,7 @@ struct divide_by_zero : std::exception {};
|
||||||
template <size_t I, size_t F>
|
template <size_t I, size_t F>
|
||||||
constexpr FixedPoint<I, F> divide(
|
constexpr FixedPoint<I, F> divide(
|
||||||
FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
|
FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
|
||||||
typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
|
std::enable_if_t<type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
|
||||||
|
|
||||||
using next_type = typename FixedPoint<I, F>::next_type;
|
using next_type = typename FixedPoint<I, F>::next_type;
|
||||||
using base_type = typename FixedPoint<I, F>::base_type;
|
using base_type = typename FixedPoint<I, F>::base_type;
|
||||||
|
@ -121,7 +123,7 @@ constexpr FixedPoint<I, F> divide(
|
||||||
template <size_t I, size_t F>
|
template <size_t I, size_t F>
|
||||||
constexpr FixedPoint<I, F> divide(
|
constexpr FixedPoint<I, F> divide(
|
||||||
FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
|
FixedPoint<I, F> numerator, FixedPoint<I, F> denominator, FixedPoint<I, F>& remainder,
|
||||||
typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
|
std::enable_if_t<!type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
|
||||||
|
|
||||||
using unsigned_type = typename FixedPoint<I, F>::unsigned_type;
|
using unsigned_type = typename FixedPoint<I, F>::unsigned_type;
|
||||||
|
|
||||||
|
@ -191,7 +193,7 @@ constexpr FixedPoint<I, F> divide(
|
||||||
template <size_t I, size_t F>
|
template <size_t I, size_t F>
|
||||||
constexpr FixedPoint<I, F> multiply(
|
constexpr FixedPoint<I, F> multiply(
|
||||||
FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
|
FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
|
||||||
typename std::enable_if<type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
|
std::enable_if_t<type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
|
||||||
|
|
||||||
using next_type = typename FixedPoint<I, F>::next_type;
|
using next_type = typename FixedPoint<I, F>::next_type;
|
||||||
using base_type = typename FixedPoint<I, F>::base_type;
|
using base_type = typename FixedPoint<I, F>::base_type;
|
||||||
|
@ -210,7 +212,7 @@ constexpr FixedPoint<I, F> multiply(
|
||||||
template <size_t I, size_t F>
|
template <size_t I, size_t F>
|
||||||
constexpr FixedPoint<I, F> multiply(
|
constexpr FixedPoint<I, F> multiply(
|
||||||
FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
|
FixedPoint<I, F> lhs, FixedPoint<I, F> rhs,
|
||||||
typename std::enable_if<!type_from_size<I + F>::next_size::is_specialized>::type* = nullptr) {
|
std::enable_if_t<!type_from_size<I + F>::next_size::is_specialized>* = nullptr) {
|
||||||
|
|
||||||
using base_type = typename FixedPoint<I, F>::base_type;
|
using base_type = typename FixedPoint<I, F>::base_type;
|
||||||
|
|
||||||
|
@ -265,15 +267,16 @@ public:
|
||||||
static constexpr base_type one = base_type(1) << fractional_bits;
|
static constexpr base_type one = base_type(1) << fractional_bits;
|
||||||
|
|
||||||
public: // constructors
|
public: // constructors
|
||||||
FixedPoint() = default;
|
constexpr FixedPoint() = default;
|
||||||
FixedPoint(const FixedPoint&) = default;
|
|
||||||
FixedPoint(FixedPoint&&) = default;
|
|
||||||
FixedPoint& operator=(const FixedPoint&) = default;
|
|
||||||
|
|
||||||
template <class Number>
|
constexpr FixedPoint(const FixedPoint&) = default;
|
||||||
constexpr FixedPoint(
|
constexpr FixedPoint& operator=(const FixedPoint&) = default;
|
||||||
Number n, typename std::enable_if<std::is_arithmetic<Number>::value>::type* = nullptr)
|
|
||||||
: data_(static_cast<base_type>(n * one)) {}
|
constexpr FixedPoint(FixedPoint&&) noexcept = default;
|
||||||
|
constexpr FixedPoint& operator=(FixedPoint&&) noexcept = default;
|
||||||
|
|
||||||
|
template <IsArithmetic Number>
|
||||||
|
constexpr FixedPoint(Number n) : data_(static_cast<base_type>(n * one)) {}
|
||||||
|
|
||||||
public: // conversion
|
public: // conversion
|
||||||
template <size_t I2, size_t F2>
|
template <size_t I2, size_t F2>
|
||||||
|
@ -301,36 +304,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public: // comparison operators
|
public: // comparison operators
|
||||||
constexpr bool operator==(FixedPoint rhs) const {
|
friend constexpr auto operator<=>(FixedPoint lhs, FixedPoint rhs) = default;
|
||||||
return data_ == rhs.data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator!=(FixedPoint rhs) const {
|
|
||||||
return data_ != rhs.data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator<(FixedPoint rhs) const {
|
|
||||||
return data_ < rhs.data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator>(FixedPoint rhs) const {
|
|
||||||
return data_ > rhs.data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator<=(FixedPoint rhs) const {
|
|
||||||
return data_ <= rhs.data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator>=(FixedPoint rhs) const {
|
|
||||||
return data_ >= rhs.data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
public: // unary operators
|
public: // unary operators
|
||||||
constexpr bool operator!() const {
|
[[nodiscard]] constexpr bool operator!() const {
|
||||||
return !data_;
|
return !data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr FixedPoint operator~() const {
|
[[nodiscard]] constexpr FixedPoint operator~() const {
|
||||||
// NOTE(eteran): this will often appear to "just negate" the value
|
// NOTE(eteran): this will often appear to "just negate" the value
|
||||||
// that is not an error, it is because -x == (~x+1)
|
// that is not an error, it is because -x == (~x+1)
|
||||||
// and that "+1" is adding an infinitesimally small fraction to the
|
// and that "+1" is adding an infinitesimally small fraction to the
|
||||||
|
@ -338,11 +319,11 @@ public: // unary operators
|
||||||
return FixedPoint::from_base(~data_);
|
return FixedPoint::from_base(~data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr FixedPoint operator-() const {
|
[[nodiscard]] constexpr FixedPoint operator-() const {
|
||||||
return FixedPoint::from_base(-data_);
|
return FixedPoint::from_base(-data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr FixedPoint operator+() const {
|
[[nodiscard]] constexpr FixedPoint operator+() const {
|
||||||
return FixedPoint::from_base(+data_);
|
return FixedPoint::from_base(+data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,15 +392,13 @@ public: // binary math operators, effects underlying bit pattern since these
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Integer,
|
template <IsIntegral Integer>
|
||||||
class = typename std::enable_if<std::is_integral<Integer>::value>::type>
|
|
||||||
constexpr FixedPoint& operator>>=(Integer n) {
|
constexpr FixedPoint& operator>>=(Integer n) {
|
||||||
data_ >>= n;
|
data_ >>= n;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Integer,
|
template <IsIntegral Integer>
|
||||||
class = typename std::enable_if<std::is_integral<Integer>::value>::type>
|
|
||||||
constexpr FixedPoint& operator<<=(Integer n) {
|
constexpr FixedPoint& operator<<=(Integer n) {
|
||||||
data_ <<= n;
|
data_ <<= n;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -430,42 +409,42 @@ public: // conversion to basic types
|
||||||
data_ += (data_ & fractional_mask) >> 1;
|
data_ += (data_ & fractional_mask) >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int to_int() {
|
[[nodiscard]] constexpr int to_int() {
|
||||||
round_up();
|
round_up();
|
||||||
return static_cast<int>((data_ & integer_mask) >> fractional_bits);
|
return static_cast<int>((data_ & integer_mask) >> fractional_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr unsigned int to_uint() const {
|
[[nodiscard]] constexpr unsigned int to_uint() {
|
||||||
round_up();
|
round_up();
|
||||||
return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
|
return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int64_t to_long() {
|
[[nodiscard]] constexpr int64_t to_long() {
|
||||||
round_up();
|
round_up();
|
||||||
return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
|
return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int to_int_floor() const {
|
[[nodiscard]] constexpr int to_int_floor() const {
|
||||||
return static_cast<int>((data_ & integer_mask) >> fractional_bits);
|
return static_cast<int>((data_ & integer_mask) >> fractional_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int64_t to_long_floor() {
|
[[nodiscard]] constexpr int64_t to_long_floor() const {
|
||||||
return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
|
return static_cast<int64_t>((data_ & integer_mask) >> fractional_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr unsigned int to_uint_floor() const {
|
[[nodiscard]] constexpr unsigned int to_uint_floor() const {
|
||||||
return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
|
return static_cast<unsigned int>((data_ & integer_mask) >> fractional_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr float to_float() const {
|
[[nodiscard]] constexpr float to_float() const {
|
||||||
return static_cast<float>(data_) / FixedPoint::one;
|
return static_cast<float>(data_) / FixedPoint::one;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr double to_double() const {
|
[[nodiscard]] constexpr double to_double() const {
|
||||||
return static_cast<double>(data_) / FixedPoint::one;
|
return static_cast<double>(data_) / FixedPoint::one;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr base_type to_raw() const {
|
[[nodiscard]] constexpr base_type to_raw() const {
|
||||||
return data_;
|
return data_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,27 +452,27 @@ public: // conversion to basic types
|
||||||
data_ &= fractional_mask;
|
data_ &= fractional_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr base_type get_frac() const {
|
[[nodiscard]] constexpr base_type get_frac() const {
|
||||||
return data_ & fractional_mask;
|
return data_ & fractional_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr void swap(FixedPoint& rhs) {
|
constexpr void swap(FixedPoint& rhs) noexcept {
|
||||||
using std::swap;
|
using std::swap;
|
||||||
swap(data_, rhs.data_);
|
swap(data_, rhs.data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
base_type data_;
|
base_type data_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// if we have the same fractional portion, but differing integer portions, we trivially upgrade the
|
// if we have the same fractional portion, but differing integer portions, we trivially upgrade the
|
||||||
// smaller type
|
// smaller type
|
||||||
template <size_t I1, size_t I2, size_t F>
|
template <size_t I1, size_t I2, size_t F>
|
||||||
constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator+(
|
constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator+(
|
||||||
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
||||||
|
|
||||||
using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
|
using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
|
||||||
|
|
||||||
const T l = T::from_base(lhs.to_raw());
|
const T l = T::from_base(lhs.to_raw());
|
||||||
const T r = T::from_base(rhs.to_raw());
|
const T r = T::from_base(rhs.to_raw());
|
||||||
|
@ -501,10 +480,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I1, size_t I2, size_t F>
|
template <size_t I1, size_t I2, size_t F>
|
||||||
constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator-(
|
constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator-(
|
||||||
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
||||||
|
|
||||||
using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
|
using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
|
||||||
|
|
||||||
const T l = T::from_base(lhs.to_raw());
|
const T l = T::from_base(lhs.to_raw());
|
||||||
const T r = T::from_base(rhs.to_raw());
|
const T r = T::from_base(rhs.to_raw());
|
||||||
|
@ -512,10 +491,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I1, size_t I2, size_t F>
|
template <size_t I1, size_t I2, size_t F>
|
||||||
constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator*(
|
constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator*(
|
||||||
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
||||||
|
|
||||||
using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
|
using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
|
||||||
|
|
||||||
const T l = T::from_base(lhs.to_raw());
|
const T l = T::from_base(lhs.to_raw());
|
||||||
const T r = T::from_base(rhs.to_raw());
|
const T r = T::from_base(rhs.to_raw());
|
||||||
|
@ -523,10 +502,10 @@ constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I1, size_t I2, size_t F>
|
template <size_t I1, size_t I2, size_t F>
|
||||||
constexpr typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type operator/(
|
constexpr std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>> operator/(
|
||||||
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
FixedPoint<I1, F> lhs, FixedPoint<I2, F> rhs) {
|
||||||
|
|
||||||
using T = typename std::conditional<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>::type;
|
using T = std::conditional_t<I1 >= I2, FixedPoint<I1, F>, FixedPoint<I2, F>>;
|
||||||
|
|
||||||
const T l = T::from_base(lhs.to_raw());
|
const T l = T::from_base(lhs.to_raw());
|
||||||
const T r = T::from_base(rhs.to_raw());
|
const T r = T::from_base(rhs.to_raw());
|
||||||
|
@ -561,54 +540,46 @@ constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, FixedPoint<I, F> rhs)
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr FixedPoint<I, F> operator+(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
lhs += FixedPoint<I, F>(rhs);
|
lhs += FixedPoint<I, F>(rhs);
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr FixedPoint<I, F> operator-(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
lhs -= FixedPoint<I, F>(rhs);
|
lhs -= FixedPoint<I, F>(rhs);
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr FixedPoint<I, F> operator*(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
lhs *= FixedPoint<I, F>(rhs);
|
lhs *= FixedPoint<I, F>(rhs);
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr FixedPoint<I, F> operator/(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
lhs /= FixedPoint<I, F>(rhs);
|
lhs /= FixedPoint<I, F>(rhs);
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator+(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr FixedPoint<I, F> operator+(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
FixedPoint<I, F> tmp(lhs);
|
FixedPoint<I, F> tmp(lhs);
|
||||||
tmp += rhs;
|
tmp += rhs;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator-(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr FixedPoint<I, F> operator-(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
FixedPoint<I, F> tmp(lhs);
|
FixedPoint<I, F> tmp(lhs);
|
||||||
tmp -= rhs;
|
tmp -= rhs;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator*(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr FixedPoint<I, F> operator*(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
FixedPoint<I, F> tmp(lhs);
|
FixedPoint<I, F> tmp(lhs);
|
||||||
tmp *= rhs;
|
tmp *= rhs;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
FixedPoint<I, F> tmp(lhs);
|
FixedPoint<I, F> tmp(lhs);
|
||||||
tmp /= rhs;
|
tmp /= rhs;
|
||||||
|
@ -616,78 +587,64 @@ constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// shift operators
|
// shift operators
|
||||||
template <size_t I, size_t F, class Integer,
|
template <size_t I, size_t F, IsIntegral Integer>
|
||||||
class = typename std::enable_if<std::is_integral<Integer>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) {
|
constexpr FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) {
|
||||||
lhs <<= rhs;
|
lhs <<= rhs;
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Integer,
|
template <size_t I, size_t F, IsIntegral Integer>
|
||||||
class = typename std::enable_if<std::is_integral<Integer>::value>::type>
|
|
||||||
constexpr FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) {
|
constexpr FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) {
|
||||||
lhs >>= rhs;
|
lhs >>= rhs;
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// comparison operators
|
// comparison operators
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator>(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr bool operator>(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
return lhs > FixedPoint<I, F>(rhs);
|
return lhs > FixedPoint<I, F>(rhs);
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator<(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr bool operator<(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
return lhs < FixedPoint<I, F>(rhs);
|
return lhs < FixedPoint<I, F>(rhs);
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator>=(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr bool operator>=(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
return lhs >= FixedPoint<I, F>(rhs);
|
return lhs >= FixedPoint<I, F>(rhs);
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator<=(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr bool operator<=(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
return lhs <= FixedPoint<I, F>(rhs);
|
return lhs <= FixedPoint<I, F>(rhs);
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator==(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr bool operator==(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
return lhs == FixedPoint<I, F>(rhs);
|
return lhs == FixedPoint<I, F>(rhs);
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator!=(FixedPoint<I, F> lhs, Number rhs) {
|
constexpr bool operator!=(FixedPoint<I, F> lhs, Number rhs) {
|
||||||
return lhs != FixedPoint<I, F>(rhs);
|
return lhs != FixedPoint<I, F>(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator>(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr bool operator>(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
return FixedPoint<I, F>(lhs) > rhs;
|
return FixedPoint<I, F>(lhs) > rhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator<(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr bool operator<(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
return FixedPoint<I, F>(lhs) < rhs;
|
return FixedPoint<I, F>(lhs) < rhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator>=(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr bool operator>=(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
return FixedPoint<I, F>(lhs) >= rhs;
|
return FixedPoint<I, F>(lhs) >= rhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator<=(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr bool operator<=(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
return FixedPoint<I, F>(lhs) <= rhs;
|
return FixedPoint<I, F>(lhs) <= rhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator==(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr bool operator==(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
return FixedPoint<I, F>(lhs) == rhs;
|
return FixedPoint<I, F>(lhs) == rhs;
|
||||||
}
|
}
|
||||||
template <size_t I, size_t F, class Number,
|
template <size_t I, size_t F, IsArithmetic Number>
|
||||||
class = typename std::enable_if<std::is_arithmetic<Number>::value>::type>
|
|
||||||
constexpr bool operator!=(Number lhs, FixedPoint<I, F> rhs) {
|
constexpr bool operator!=(Number lhs, FixedPoint<I, F> rhs) {
|
||||||
return FixedPoint<I, F>(lhs) != rhs;
|
return FixedPoint<I, F>(lhs) != rhs;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue