From bc6a2b7d0294acb9c4c5a9c5ec9c35f1cdaa7907 Mon Sep 17 00:00:00 2001 From: Pharap <2933055+Pharap@users.noreply.github.com> Date: Fri, 8 Jun 2018 16:55:26 +0100 Subject: [PATCH] Add pure fractional specialisations --- src/FixedPoints/SFixed.h | 101 ++++++++++++ src/FixedPoints/SFixedFreeFunctions.h | 198 ++++++++++++++++++++++++ src/FixedPoints/SFixedMemberFunctions.h | 153 ++++++++++++++++++ src/FixedPoints/UFixed.h | 102 ++++++++++++ src/FixedPoints/UFixedFreeFunctions.h | 197 +++++++++++++++++++++++ src/FixedPoints/UFixedMemberFunctions.h | 138 +++++++++++++++++ src/FixedPoints/Utils.h | 24 +++ 7 files changed, 913 insertions(+) diff --git a/src/FixedPoints/SFixed.h b/src/FixedPoints/SFixed.h index da7ad3a..c43c3a0 100644 --- a/src/FixedPoints/SFixed.h +++ b/src/FixedPoints/SFixed.h @@ -125,6 +125,107 @@ public: constexpr const static SFixed Tau = 6.2831853071795864769252867665590057683943; }; +// +// Fraction-only Specialisation +// + +template< unsigned Fraction > +class SFixed<0, Fraction> +{ +public: + constexpr const static uintmax_t IntegerSize = 1; + constexpr const static uintmax_t FractionSize = Fraction; + constexpr const static uintmax_t LogicalSize = IntegerSize + FractionSize; + constexpr const static uintmax_t Scale = UINTMAX_C(1) << FractionSize; + +public: + static_assert(LogicalSize <= FIXED_POINTS_DETAILS::BitSize::Value, "Platform does not have a native type large enough for SFixed."); + +public: + using IntegerType = FIXED_POINTS_DETAILS::LeastInt; + using FractionType = FIXED_POINTS_DETAILS::LeastUInt; + using InternalType = FIXED_POINTS_DETAILS::LeastInt; + + constexpr const static uintmax_t InternalSize = FIXED_POINTS_DETAILS::BitSize::Value; + + using ShiftType = FIXED_POINTS_DETAILS::LeastUInt; + using MaskType = FIXED_POINTS_DETAILS::LeastUInt; + +public: + constexpr const static ShiftType IntegerShift = FractionSize; + constexpr const static ShiftType FractionShift = 0; + + constexpr const static MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + constexpr const static MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + + constexpr const static MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift); + + constexpr const static MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask::Value; + constexpr const static MaskType LesserMidpointMask = MidpointMask - 1; + +protected: + class RawType + { + private: + const InternalType value; + + public: + constexpr inline explicit RawType(const InternalType & value) : value(value) {} + constexpr inline explicit operator InternalType(void) const { return this->value; } + }; + +protected: + InternalType value; + +protected: + constexpr SFixed(const RawType & value); + +public: + constexpr SFixed(void); + constexpr SFixed(const IntegerType & integer, const FractionType & fraction); + constexpr SFixed(const char & value) = delete; + constexpr SFixed(const unsigned char & value) = delete; + constexpr SFixed(const signed char & value) = delete; + constexpr SFixed(const unsigned short int & value) = delete; + constexpr SFixed(const signed short int & value) = delete; + constexpr SFixed(const unsigned int & value) = delete; + constexpr SFixed(const signed int & value) = delete; + constexpr SFixed(const unsigned long int & value) = delete; + constexpr SFixed(const signed long int & value) = delete; + constexpr SFixed(const unsigned long long int & value) = delete; + constexpr SFixed(const signed long long int & value) = delete; + constexpr SFixed(const double & value); + constexpr SFixed(const float & value); + constexpr SFixed(const long double & value); + + constexpr InternalType getInternal(void) const; + constexpr IntegerType getInteger(void) const; + constexpr FractionType getFraction(void) const; + + constexpr explicit operator IntegerType(void) const; + constexpr explicit operator float(void) const; + constexpr explicit operator double(void) const; + constexpr explicit operator long double(void) const; + + template< unsigned IntegerOut, unsigned FractionOut > + constexpr explicit operator SFixed(void) const; + + constexpr static SFixed fromInternal(const InternalType & value); + + constexpr SFixed operator -(void) const; + SFixed & operator +=(const SFixed & other); + SFixed & operator -=(const SFixed & other); + SFixed & operator *=(const SFixed & other); + SFixed & operator /=(const SFixed & other); + +public: + constexpr const static SFixed Epsilon = SFixed::fromInternal(1); + constexpr const static SFixed MinValue = SFixed::fromInternal(FIXED_POINTS_DETAILS::MsbMask::Value); + constexpr const static SFixed MaxValue = SFixed::fromInternal(~FIXED_POINTS_DETAILS::MsbMask::Value); + + // Pi, E, Phi and Tau will never be representable by 0 integer fixed points +}; + // // Free functions diff --git a/src/FixedPoints/SFixedFreeFunctions.h b/src/FixedPoints/SFixedFreeFunctions.h index 1fe5047..662d2ff 100644 --- a/src/FixedPoints/SFixedFreeFunctions.h +++ b/src/FixedPoints/SFixedFreeFunctions.h @@ -320,4 +320,202 @@ OPERATORS( signed long long int ) #undef ARITHMETIC_OPERATOR #undef LOGIC_OPERATOR + +// +// Literal-type Operators +// Generated by macro to make maintenance easier +// + +#define LOGIC_OPERATOR( type, op )\ + template< unsigned Fraction >\ + constexpr bool operator op (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return (left op SFixed<0, Fraction>(right));\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator op (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return (SFixed<0, Fraction>(left) op right);\ + } + +#define DELETED_LOGIC_OPERATOR_EQ( type )\ + template< unsigned Fraction >\ + constexpr bool operator == (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return false;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator == (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return false;\ + } + +#define DELETED_LOGIC_OPERATOR_NE( type )\ + template< unsigned Fraction >\ + constexpr bool operator != (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return true;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator != (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return true;\ + } + +#define DELETED_LOGIC_OPERATOR_LT( type )\ + template< unsigned Fraction >\ + constexpr bool operator < (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return true;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator < (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return false;\ + } + +#define DELETED_LOGIC_OPERATOR_LTE( type )\ + template< unsigned Fraction >\ + constexpr bool operator <= (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return true;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator <= (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return false;\ + } + +#define DELETED_LOGIC_OPERATOR_GT( type )\ + template< unsigned Fraction >\ + constexpr bool operator > (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return false;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator > (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return true;\ + } + +#define DELETED_LOGIC_OPERATOR_GTE( type )\ + template< unsigned Fraction >\ + constexpr bool operator >= (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return false;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator >= (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return true;\ + } + +#define ARITHMETIC_OPERATOR( type, op )\ + template< unsigned Fraction >\ + constexpr SFixed<0, Fraction> operator op (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return (left op SFixed<0, Fraction>(right));\ + }\ + \ + template< unsigned Fraction >\ + constexpr SFixed<0, Fraction> operator op (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return (SFixed<0, Fraction>(left) op right);\ + } + +#define DELETED_ARITHMETIC_OPERATOR( type, op )\ + template< unsigned Fraction >\ + constexpr SFixed<0, Fraction> operator op (const SFixed<0, Fraction> & left, const type & right)\ + {\ + return 0;\ + }\ + \ + template< unsigned Fraction >\ + constexpr SFixed<0, Fraction> operator op (const type & left, const SFixed<0, Fraction> & right)\ + {\ + return 0;\ + } + +#define LOGIC_OPERATORS( type ) \ + LOGIC_OPERATOR( type, == )\ + LOGIC_OPERATOR( type, != )\ + LOGIC_OPERATOR( type, < )\ + LOGIC_OPERATOR( type, <= )\ + LOGIC_OPERATOR( type, > )\ + LOGIC_OPERATOR( type, >= ) + +#define ARITHMETIC_OPERATORS( type ) \ + ARITHMETIC_OPERATOR( type, + )\ + ARITHMETIC_OPERATOR( type, - )\ + ARITHMETIC_OPERATOR( type, * )\ + ARITHMETIC_OPERATOR( type, / ) + +#define DELETED_LOGIC_OPERATORS( type ) \ + DELETED_LOGIC_OPERATOR_EQ( type )\ + DELETED_LOGIC_OPERATOR_NE( type )\ + DELETED_LOGIC_OPERATOR_LT( type )\ + DELETED_LOGIC_OPERATOR_LTE( type )\ + DELETED_LOGIC_OPERATOR_GT( type )\ + DELETED_LOGIC_OPERATOR_GTE( type ) + +#define DELETED_ARITHMETIC_OPERATORS( type ) \ + DELETED_ARITHMETIC_OPERATOR( type, + )\ + DELETED_ARITHMETIC_OPERATOR( type, - )\ + DELETED_ARITHMETIC_OPERATOR( type, * )\ + DELETED_ARITHMETIC_OPERATOR( type, / ) + +#define OPERATORS( type ) \ + LOGIC_OPERATORS( type )\ + ARITHMETIC_OPERATORS( type ) + +#define DELETED_OPERATORS( type ) \ + DELETED_LOGIC_OPERATORS( type )\ + DELETED_ARITHMETIC_OPERATORS( type ) + +OPERATORS( float ) +OPERATORS( double ) +OPERATORS( long double ) + +DELETED_OPERATORS( char ) +DELETED_OPERATORS( unsigned char ) +DELETED_OPERATORS( signed char ) +DELETED_OPERATORS( unsigned short int ) +DELETED_OPERATORS( signed short int ) +DELETED_OPERATORS( unsigned int ) +DELETED_OPERATORS( signed int ) +DELETED_OPERATORS( unsigned long int ) +DELETED_OPERATORS( signed long int ) +DELETED_OPERATORS( unsigned long long int ) +DELETED_OPERATORS( signed long long int ) + +// Prevent Macro-bleed: + +#undef DELETED_OPERATORS +#undef OPERATORS + +#undef DELETED_ARITHMETIC_OPERATORS +#undef DELETED_LOGIC_OPERATORS + +#undef ARITHMETIC_OPERATORS +#undef LOGIC_OPERATORS + +#undef DELETED_ARITHMETIC_OPERATOR +#undef ARITHMETIC_OPERATOR + +#undef DELETED_LOGIC_OPERATOR_EQ +#undef DELETED_LOGIC_OPERATOR_NE +#undef DELETED_LOGIC_OPERATOR_LT +#undef DELETED_LOGIC_OPERATOR_LTE +#undef DELETED_LOGIC_OPERATOR_GT +#undef DELETED_LOGIC_OPERATOR_GTE + +#undef LOGIC_OPERATOR + FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/src/FixedPoints/SFixedMemberFunctions.h b/src/FixedPoints/SFixedMemberFunctions.h index e11b8ef..df872f7 100644 --- a/src/FixedPoints/SFixedMemberFunctions.h +++ b/src/FixedPoints/SFixedMemberFunctions.h @@ -24,18 +24,37 @@ constexpr SFixed::SFixed(const RawType & value) { } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::SFixed(const RawType & value) + : value(static_cast(value)) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::SFixed(void) : value(0) { } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::SFixed(void) + : value(0) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::SFixed(const IntegerType & integer, const FractionType & fraction) : value((static_cast(integer) << FractionSize) | fraction) { } +// The comma operator and void cast are used to circumvent an unused parameter warning +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::SFixed(const IntegerType & integer, const FractionType & fraction) + : value(((void)integer, fraction)) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::SFixed(const char & value) : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) @@ -108,18 +127,36 @@ constexpr SFixed::SFixed(const double & value) { } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::SFixed(const double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::SFixed(const float & value) : value(static_cast(value * static_cast(Scale))) { } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::SFixed(const float & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::SFixed(const long double & value) : value(static_cast(value * static_cast(Scale))) { } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::SFixed(const long double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + // // Getters // @@ -130,18 +167,36 @@ constexpr typename SFixed::InternalType SFixedvalue; } +template< unsigned Fraction > +constexpr typename SFixed<0, Fraction>::InternalType SFixed<0, Fraction>::getInternal(void) const +{ + return this->value; +} + template< unsigned Integer, unsigned Fraction > constexpr typename SFixed::IntegerType SFixed::getInteger(void) const { return (static_cast(this->value >> IntegerShift) & IntegerMask) | ((this->value < 0) ? ~IntegerMask : 0); } +template< unsigned Fraction > +constexpr typename SFixed<0, Fraction>::IntegerType SFixed<0, Fraction>::getInteger(void) const +{ + return (static_cast(this->value >> IntegerShift) & IntegerMask) | ((this->value < 0) ? ~IntegerMask : 0); +} + template< unsigned Integer, unsigned Fraction > constexpr typename SFixed::FractionType SFixed::getFraction(void) const { return static_cast(this->value >> FractionShift) & FractionMask; } +template< unsigned Fraction > +constexpr typename SFixed<0, Fraction>::FractionType SFixed<0, Fraction>::getFraction(void) const +{ + return static_cast(this->value >> FractionShift) & FractionMask; +} + // // Cast Operators // @@ -152,6 +207,12 @@ constexpr SFixed::operator IntegerType(void) const return this->getInteger(); } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::operator IntegerType(void) const +{ + return this->getInteger(); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::operator float(void) const { @@ -161,6 +222,15 @@ constexpr SFixed::operator float(void) const ((this->value < 0) ? ~IdentityMask : 0)); } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::operator float(void) const +{ + return (1.0F / Scale) * + static_cast + ((this->value & IdentityMask) | + ((this->value < 0) ? ~IdentityMask : 0)); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::operator double(void) const { @@ -170,6 +240,15 @@ constexpr SFixed::operator double(void) const ((this->value < 0) ? ~IdentityMask : 0)); } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::operator double(void) const +{ + return (1.0 / Scale) * + static_cast + ((this->value & IdentityMask) | + ((this->value < 0) ? ~IdentityMask : 0)); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed::operator long double(void) const { @@ -179,6 +258,15 @@ constexpr SFixed::operator long double(void) const ((this->value < 0) ? ~IdentityMask : 0)); } +template< unsigned Fraction > +constexpr SFixed<0, Fraction>::operator long double(void) const +{ + return (1.0L / Scale) * + static_cast + ((this->value & IdentityMask) | + ((this->value < 0) ? ~IdentityMask : 0)); +} + template< unsigned Integer, unsigned Fraction > template< unsigned IntegerOut, unsigned FractionOut > constexpr SFixed::operator SFixed(void) const @@ -198,6 +286,25 @@ constexpr SFixed::operator SFixed(vo OutputType::fromInternal(this->value); } +template< unsigned Fraction > +template< unsigned IntegerOut, unsigned FractionOut > +constexpr SFixed<0, Fraction>::operator SFixed(void) const +{ + using OutputType = SFixed; + using OutputInternalType = typename OutputType::InternalType; + using OutputShiftType = typename OutputType::ShiftType; + + using InputType = SFixed<0, Fraction>; + using InputShiftType = typename InputType::ShiftType; + + return + (FractionOut > FractionSize) ? + OutputType::fromInternal(static_cast(static_cast(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) : + (FractionSize > FractionOut) ? + OutputType::fromInternal(static_cast(static_cast(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) : + OutputType::fromInternal(this->value); +} + // // Static Functions // @@ -208,12 +315,24 @@ constexpr SFixed SFixed::fromInternal(cons return SFixed(RawType(value)); } +template< unsigned Fraction > +constexpr SFixed<0, Fraction> SFixed<0, Fraction>::fromInternal(const typename SFixed<0, Fraction>::InternalType & value) +{ + return SFixed<0, Fraction>(RawType(value)); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed SFixed::operator -(void) const { return SFixed::fromInternal(-this->value); } +template< unsigned Fraction > +constexpr SFixed<0, Fraction> SFixed<0, Fraction>::operator -(void) const +{ + return SFixed<0, Fraction>::fromInternal(-this->value); +} + // // Member Operators // @@ -243,6 +362,13 @@ SFixed & SFixed::operator +=(const SFixed< return *this; } +template< unsigned Fraction > +SFixed<0, Fraction> & SFixed<0, Fraction>::operator +=(const SFixed<0, Fraction> & other) +{ + this->value += other.value; + return *this; +} + template< unsigned Integer, unsigned Fraction > SFixed & SFixed::operator -=(const SFixed & other) { @@ -250,6 +376,13 @@ SFixed & SFixed::operator -=(const SFixed< return *this; } +template< unsigned Fraction > +SFixed<0, Fraction> & SFixed<0, Fraction>::operator -=(const SFixed<0, Fraction> & other) +{ + this->value -= other.value; + return *this; +} + template< unsigned Integer, unsigned Fraction > SFixed & SFixed::operator *=(const SFixed & other) { @@ -260,6 +393,16 @@ SFixed & SFixed::operator *=(const SFixed< return *this; } +template< unsigned Fraction > +SFixed<0, Fraction> & SFixed<0, Fraction>::operator *=(const SFixed<0, Fraction> & other) +{ + using InternalType = typename SFixed<0, Fraction>::InternalType; + using PrecisionType = typename SFixed<0, Fraction * 2>::InternalType; + const PrecisionType temp = (static_cast(this->value) * static_cast(other.value)) >> Fraction; + this->value = static_cast(temp); + return *this; +} + template< unsigned Integer, unsigned Fraction > SFixed & SFixed::operator /=(const SFixed & other) { @@ -270,4 +413,14 @@ SFixed & SFixed::operator /=(const SFixed< return *this; } +template< unsigned Fraction > +SFixed<0, Fraction> & SFixed<0, Fraction>::operator /=(const SFixed<0, Fraction> & other) +{ + using InternalType = typename SFixed<0, Fraction>::InternalType; + using PrecisionType = typename SFixed<0, Fraction * 2>::InternalType; + const PrecisionType temp = (static_cast(this->value) << Fraction) / static_cast(other.value); + this->value = static_cast(temp); + return *this; +} + FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/src/FixedPoints/UFixed.h b/src/FixedPoints/UFixed.h index 34344eb..52a54d7 100644 --- a/src/FixedPoints/UFixed.h +++ b/src/FixedPoints/UFixed.h @@ -125,6 +125,108 @@ public: constexpr const static UFixed Tau = 6.2831853071795864769252867665590057683943; }; +// +// Fraction-only Specialisation +// + + +template< unsigned Fraction > +class UFixed<0, Fraction> +{ +public: + constexpr const static uintmax_t IntegerSize = 0; + constexpr const static uintmax_t FractionSize = Fraction; + constexpr const static uintmax_t LogicalSize = IntegerSize + FractionSize; + constexpr const static uintmax_t Scale = UINTMAX_C(1) << FractionSize; + +public: + static_assert(LogicalSize <= FIXED_POINTS_DETAILS::BitSize::Value, "Platform does not have a native type large enough for UFixed."); + +public: + using IntegerType = FIXED_POINTS_DETAILS::LeastUInt; + using FractionType = FIXED_POINTS_DETAILS::LeastUInt; + using InternalType = FIXED_POINTS_DETAILS::LeastUInt; + + constexpr const static uintmax_t InternalSize = FIXED_POINTS_DETAILS::BitSize::Value; + + using ShiftType = FIXED_POINTS_DETAILS::LeastUInt; + using MaskType = FIXED_POINTS_DETAILS::LeastUInt; + +public: + constexpr const static ShiftType IntegerShift = FractionSize; + constexpr const static ShiftType FractionShift = 0; + + constexpr const static MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + constexpr const static MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + + constexpr const static MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift); + + constexpr const static MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask::Value; + constexpr const static MaskType LesserMidpointMask = MidpointMask - 1; + +protected: + class RawType + { + private: + const InternalType value; + + public: + constexpr inline explicit RawType(const InternalType & value) : value(value) {} + constexpr inline explicit operator InternalType(void) const { return this->value; } + }; + +protected: + InternalType value; + +protected: + constexpr UFixed(const RawType & value); + +public: + constexpr UFixed(void); + constexpr UFixed(const IntegerType & integer, const FractionType & fraction); + constexpr UFixed(const char & value) = delete; + constexpr UFixed(const unsigned char & value) = delete; + constexpr UFixed(const signed char & value) = delete; + constexpr UFixed(const unsigned short int & value) = delete; + constexpr UFixed(const signed short int & value) = delete; + constexpr UFixed(const unsigned int & value) = delete; + constexpr UFixed(const signed int & value) = delete; + constexpr UFixed(const unsigned long int & value) = delete; + constexpr UFixed(const signed long int & value) = delete; + constexpr UFixed(const unsigned long long int & value) = delete; + constexpr UFixed(const signed long long int & value) = delete; + constexpr UFixed(const double & value); + constexpr UFixed(const float & value); + constexpr UFixed(const long double & value); + +public: + constexpr InternalType getInternal(void) const; + constexpr IntegerType getInteger(void) const; + constexpr FractionType getFraction(void) const; + + constexpr explicit operator IntegerType(void) const; + constexpr explicit operator float(void) const; + constexpr explicit operator double(void) const; + constexpr explicit operator long double(void) const; + + template< unsigned IntegerOut, unsigned FractionOut > + constexpr explicit operator UFixed(void) const; + + constexpr static UFixed fromInternal(const InternalType & value); + + UFixed & operator +=(const UFixed & other); + UFixed & operator -=(const UFixed & other); + UFixed & operator *=(const UFixed & other); + UFixed & operator /=(const UFixed & other); + +public: + constexpr const static UFixed Epsilon = UFixed::fromInternal(1); + constexpr const static UFixed MinValue = UFixed::fromInternal(0); + constexpr const static UFixed MaxValue = UFixed::fromInternal(~0); + + // Pi, E, Phi and Tau will never be representable by 0 integer fixed points +}; + // // Free functions diff --git a/src/FixedPoints/UFixedFreeFunctions.h b/src/FixedPoints/UFixedFreeFunctions.h index 55b042e..7ee6b45 100644 --- a/src/FixedPoints/UFixedFreeFunctions.h +++ b/src/FixedPoints/UFixedFreeFunctions.h @@ -320,4 +320,201 @@ OPERATORS( signed long long int ) #undef ARITHMETIC_OPERATOR #undef LOGIC_OPERATOR +// +// Literal-type Operators +// Generated by macro to make maintenance easier +// + +#define LOGIC_OPERATOR( type, op )\ + template< unsigned Fraction >\ + constexpr bool operator op (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return (left op UFixed<0, Fraction>(right));\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator op (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return (UFixed<0, Fraction>(left) op right);\ + } + +#define DELETED_LOGIC_OPERATOR_EQ( type )\ + template< unsigned Fraction >\ + constexpr bool operator == (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return false;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator == (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return false;\ + } + +#define DELETED_LOGIC_OPERATOR_NE( type )\ + template< unsigned Fraction >\ + constexpr bool operator != (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return true;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator != (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return true;\ + } + +#define DELETED_LOGIC_OPERATOR_LT( type )\ + template< unsigned Fraction >\ + constexpr bool operator < (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return true;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator < (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return false;\ + } + +#define DELETED_LOGIC_OPERATOR_LTE( type )\ + template< unsigned Fraction >\ + constexpr bool operator <= (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return true;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator <= (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return false;\ + } + +#define DELETED_LOGIC_OPERATOR_GT( type )\ + template< unsigned Fraction >\ + constexpr bool operator > (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return false;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator > (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return true;\ + } + +#define DELETED_LOGIC_OPERATOR_GTE( type )\ + template< unsigned Fraction >\ + constexpr bool operator >= (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return false;\ + }\ + \ + template< unsigned Fraction >\ + constexpr bool operator >= (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return true;\ + } + +#define ARITHMETIC_OPERATOR( type, op )\ + template< unsigned Fraction >\ + constexpr UFixed<0, Fraction> operator op (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return (left op UFixed<0, Fraction>(right));\ + }\ + \ + template< unsigned Fraction >\ + constexpr UFixed<0, Fraction> operator op (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return (UFixed<0, Fraction>(left) op right);\ + } + +#define DELETED_ARITHMETIC_OPERATOR( type, op )\ + template< unsigned Fraction >\ + constexpr UFixed<0, Fraction> operator op (const UFixed<0, Fraction> & left, const type & right)\ + {\ + return 0;\ + }\ + \ + template< unsigned Fraction >\ + constexpr UFixed<0, Fraction> operator op (const type & left, const UFixed<0, Fraction> & right)\ + {\ + return 0;\ + } + +#define LOGIC_OPERATORS( type ) \ + LOGIC_OPERATOR( type, == )\ + LOGIC_OPERATOR( type, != )\ + LOGIC_OPERATOR( type, < )\ + LOGIC_OPERATOR( type, <= )\ + LOGIC_OPERATOR( type, > )\ + LOGIC_OPERATOR( type, >= ) + +#define ARITHMETIC_OPERATORS( type ) \ + ARITHMETIC_OPERATOR( type, + )\ + ARITHMETIC_OPERATOR( type, - )\ + ARITHMETIC_OPERATOR( type, * )\ + ARITHMETIC_OPERATOR( type, / ) + +#define DELETED_LOGIC_OPERATORS( type ) \ + DELETED_LOGIC_OPERATOR_EQ( type )\ + DELETED_LOGIC_OPERATOR_NE( type )\ + DELETED_LOGIC_OPERATOR_LT( type )\ + DELETED_LOGIC_OPERATOR_LTE( type )\ + DELETED_LOGIC_OPERATOR_GT( type )\ + DELETED_LOGIC_OPERATOR_GTE( type ) + +#define DELETED_ARITHMETIC_OPERATORS( type ) \ + DELETED_ARITHMETIC_OPERATOR( type, + )\ + DELETED_ARITHMETIC_OPERATOR( type, - )\ + DELETED_ARITHMETIC_OPERATOR( type, * )\ + DELETED_ARITHMETIC_OPERATOR( type, / ) + +#define OPERATORS( type ) \ + LOGIC_OPERATORS( type )\ + ARITHMETIC_OPERATORS( type ) + +#define DELETED_OPERATORS( type ) \ + DELETED_LOGIC_OPERATORS( type )\ + DELETED_ARITHMETIC_OPERATORS( type ) + +OPERATORS( float ) +OPERATORS( double ) +OPERATORS( long double ) + +DELETED_OPERATORS( char ) +DELETED_OPERATORS( unsigned char ) +DELETED_OPERATORS( signed char ) +DELETED_OPERATORS( unsigned short int ) +DELETED_OPERATORS( signed short int ) +DELETED_OPERATORS( unsigned int ) +DELETED_OPERATORS( signed int ) +DELETED_OPERATORS( unsigned long int ) +DELETED_OPERATORS( signed long int ) +DELETED_OPERATORS( unsigned long long int ) +DELETED_OPERATORS( signed long long int ) + +// Prevent Macro-bleed: + +#undef DELETED_OPERATORS +#undef OPERATORS + +#undef DELETED_ARITHMETIC_OPERATORS +#undef DELETED_LOGIC_OPERATORS + +#undef ARITHMETIC_OPERATORS +#undef LOGIC_OPERATORS + +#undef DELETED_ARITHMETIC_OPERATOR +#undef ARITHMETIC_OPERATOR + +#undef DELETED_LOGIC_OPERATOR_EQ +#undef DELETED_LOGIC_OPERATOR_NE +#undef DELETED_LOGIC_OPERATOR_LT +#undef DELETED_LOGIC_OPERATOR_LTE +#undef DELETED_LOGIC_OPERATOR_GT +#undef DELETED_LOGIC_OPERATOR_GTE + +#undef LOGIC_OPERATOR + FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/src/FixedPoints/UFixedMemberFunctions.h b/src/FixedPoints/UFixedMemberFunctions.h index 69f99e0..6329f35 100644 --- a/src/FixedPoints/UFixedMemberFunctions.h +++ b/src/FixedPoints/UFixedMemberFunctions.h @@ -24,18 +24,37 @@ constexpr UFixed::UFixed(const RawType & value) { } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::UFixed(const RawType & value) + : value(static_cast(value)) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::UFixed(void) : value(0) { } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::UFixed(void) + : value(0) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::UFixed(const IntegerType & integer, const FractionType & fraction) : value((static_cast(integer) << FractionSize) | fraction) { } +// The comma operator and void cast are used to circumvent an unused parameter warning +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::UFixed(const IntegerType & integer, const FractionType & fraction) + : value(((void)integer, fraction)) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::UFixed(const char & value) : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) @@ -108,18 +127,36 @@ constexpr UFixed::UFixed(const double & value) { } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::UFixed(const double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::UFixed(const float & value) : value(static_cast(value * static_cast(Scale))) { } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::UFixed(const float & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::UFixed(const long double & value) : value(static_cast(value * static_cast(Scale))) { } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::UFixed(const long double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + // // Getters // @@ -130,18 +167,36 @@ constexpr typename UFixed::InternalType UFixedvalue; } +template< unsigned Fraction > +constexpr typename UFixed<0, Fraction>::InternalType UFixed<0, Fraction>::getInternal(void) const +{ + return this->value; +} + template< unsigned Integer, unsigned Fraction > constexpr typename UFixed::IntegerType UFixed::getInteger(void) const { return static_cast(this->value >> IntegerShift) & IntegerMask; } +template< unsigned Fraction > +constexpr typename UFixed<0, Fraction>::IntegerType UFixed<0, Fraction>::getInteger(void) const +{ + return 0; +} + template< unsigned Integer, unsigned Fraction > constexpr typename UFixed::FractionType UFixed::getFraction(void) const { return static_cast(this->value >> FractionShift) & FractionMask; } +template< unsigned Fraction > +constexpr typename UFixed<0, Fraction>::FractionType UFixed<0, Fraction>::getFraction(void) const +{ + return static_cast(this->value) & FractionMask; +} + // // Cast Operators // @@ -152,18 +207,42 @@ constexpr UFixed::operator IntegerType(void) const return this->getInteger(); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::operator IntegerType(void) const +{ + return this->getInteger(); +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::operator float(void) const { return ((this->value & IdentityMask) * (1.0F / Scale)); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::operator float(void) const +{ + return ((this->value & IdentityMask) * (1.0F / Scale)); +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::operator double(void) const { return ((this->value & IdentityMask) * (1.0 / Scale)); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::operator double(void) const +{ + return ((this->value & IdentityMask) * (1.0 / Scale)); +} + +template< unsigned Fraction > +constexpr UFixed<0, Fraction>::operator long double(void) const +{ + return ((this->value & IdentityMask) * (1.0L / Scale)); +} + template< unsigned Integer, unsigned Fraction > constexpr UFixed::operator long double(void) const { @@ -189,6 +268,25 @@ constexpr UFixed::operator UFixed(vo OutputType::fromInternal(this->value); } +template< unsigned Fraction > +template< unsigned IntegerOut, unsigned FractionOut > +constexpr UFixed<0, Fraction>::operator UFixed(void) const +{ + using OutputType = UFixed; + using OutputInternalType = typename OutputType::InternalType; + using OutputShiftType = typename OutputType::ShiftType; + + using InputType = UFixed<0, Fraction>; + using InputShiftType = typename InputType::ShiftType; + + return + (FractionOut > FractionSize) ? + OutputType::fromInternal(static_cast(static_cast(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) : + (FractionSize > FractionOut) ? + OutputType::fromInternal(static_cast(static_cast(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) : + OutputType::fromInternal(this->value); +} + // // Static Functions // @@ -199,6 +297,12 @@ constexpr UFixed UFixed::fromInternal(cons return UFixed(RawType(value)); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction> UFixed<0, Fraction>::fromInternal(const typename UFixed<0, Fraction>::InternalType & value) +{ + return UFixed<0, Fraction>(RawType(value)); +} + // // Member Operators // @@ -228,6 +332,13 @@ UFixed & UFixed::operator +=(const UFixed< return *this; } +template< unsigned Fraction > +UFixed<0, Fraction> & UFixed<0, Fraction>::operator +=(const UFixed<0, Fraction> & other) +{ + this->value += other.value; + return *this; +} + template< unsigned Integer, unsigned Fraction > UFixed & UFixed::operator -=(const UFixed & other) { @@ -235,6 +346,13 @@ UFixed & UFixed::operator -=(const UFixed< return *this; } +template< unsigned Fraction > +UFixed<0, Fraction> & UFixed<0, Fraction>::operator -=(const UFixed<0, Fraction> & other) +{ + this->value -= other.value; + return *this; +} + template< unsigned Integer, unsigned Fraction > UFixed & UFixed::operator *=(const UFixed & other) { @@ -245,6 +363,16 @@ UFixed & UFixed::operator *=(const UFixed< return *this; } +template< unsigned Fraction > +UFixed<0, Fraction> & UFixed<0, Fraction>::operator *=(const UFixed<0, Fraction> & other) +{ + using InternalType = typename UFixed<0, Fraction>::InternalType; + using PrecisionType = typename UFixed<0, Fraction * 2>::InternalType; + const PrecisionType temp = (static_cast(this->value) * static_cast(other.value)) >> FractionSize; + this->value = static_cast(temp); + return *this; +} + template< unsigned Integer, unsigned Fraction > UFixed & UFixed::operator /=(const UFixed & other) { @@ -255,4 +383,14 @@ UFixed & UFixed::operator /=(const UFixed< return *this; } +template< unsigned Fraction > +UFixed<0, Fraction> & UFixed<0, Fraction>::operator /=(const UFixed<0, Fraction> & other) +{ + using InternalType = typename UFixed<0, Fraction>::InternalType; + using PrecisionType = typename UFixed<0, Fraction * 2>::InternalType; + const PrecisionType temp = (static_cast(this->value) << FractionSize) / static_cast(other.value); + this->value = static_cast(temp); + return *this; +} + FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/src/FixedPoints/Utils.h b/src/FixedPoints/Utils.h index 0d1cf6b..cc94e35 100644 --- a/src/FixedPoints/Utils.h +++ b/src/FixedPoints/Utils.h @@ -103,6 +103,12 @@ constexpr UFixed floorFixed(const UFixed & return OutputType::fromInternal(static_cast(value.getInternal() & ~OutputType::FractionMask)); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction> floorFixed(const UFixed<0, Fraction> & value) +{ + return UFixed<0, Fraction>(0, 0); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed floorFixed(const SFixed & value) { @@ -117,6 +123,12 @@ constexpr UFixed ceilFixed(const UFixed & return UFixed((value.getFraction() == 0) ? value.getInteger() : (value.getInteger() + 1), 0); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction> ceilFixed(const UFixed<0, Fraction> & value) +{ + return UFixed<0, Fraction>(0, 0); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed ceilFixed(const SFixed & value) { @@ -130,6 +142,12 @@ constexpr UFixed roundFixed(const UFixed & return (value.getFraction() >= OutputType(0.5).getFraction()) ? ceilFixed(value) : floorFixed(value); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction> roundFixed(const UFixed<0, Fraction> & value) +{ + return UFixed<0, Fraction>(0, 0); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed roundFixed(const SFixed & value) { @@ -146,6 +164,12 @@ constexpr UFixed truncFixed(const UFixed & return UFixed(value.getInteger(), 0); } +template< unsigned Fraction > +constexpr UFixed<0, Fraction> truncFixed(const UFixed<0, Fraction> & value) +{ + return UFixed<0, Fraction>(0, 0); +} + template< unsigned Integer, unsigned Fraction > constexpr SFixed truncFixed(const SFixed & value) {