FIXED_POINTS_BEGIN_NAMESPACE // // multiply // template< unsigned Integer, unsigned Fraction > constexpr SFixed multiply(const SFixed & left, const SFixed & right) { using ResultType = SFixed; using InternalType = typename ResultType::InternalType; return ResultType::fromInternal(static_cast(static_cast(left.getInternal()) * static_cast(right.getInternal()))); } // // Basic Logic Operations // template< unsigned Integer, unsigned Fraction > constexpr bool operator ==(const SFixed & left, const SFixed & right) { return (left.getInternal() == right.getInternal()); } template< unsigned Integer, unsigned Fraction > constexpr bool operator !=(const SFixed & left, const SFixed & right) { return (left.getInternal() != right.getInternal()); } template< unsigned Integer, unsigned Fraction > constexpr bool operator <(const SFixed & left, const SFixed & right) { return (left.getInternal() < right.getInternal()); } template< unsigned Integer, unsigned Fraction > constexpr bool operator >(const SFixed & left, const SFixed & right) { return (left.getInternal() > right.getInternal()); } template< unsigned Integer, unsigned Fraction > constexpr bool operator <=(const SFixed & left, const SFixed & right) { return (left.getInternal() <= right.getInternal()); } template< unsigned Integer, unsigned Fraction > constexpr bool operator >=(const SFixed & left, const SFixed & right) { return (left.getInternal() >= right.getInternal()); } // // Inter-size Logic Operations // template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr bool operator ==(const SFixed & left, const SFixed & right) { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) == static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr bool operator !=(const SFixed & left, const SFixed & right) { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) != static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr bool operator <(const SFixed & left, const SFixed & right) { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) < static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr bool operator >(const SFixed & left, const SFixed & right) { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) > static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr bool operator <=(const SFixed & left, const SFixed & right) { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) <= static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr bool operator >=(const SFixed & left, const SFixed & right) { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) >= static_cast(right)); } // // Basic Arithmetic Operations // template< unsigned Integer, unsigned Fraction > constexpr SFixed operator +(const SFixed & left, const SFixed & right) { using InternalType = typename SFixed::InternalType; return SFixed::fromInternal(static_cast(left.getInternal() + right.getInternal())); } template< unsigned Integer, unsigned Fraction > constexpr SFixed operator -(const SFixed & left, const SFixed & right) { using InternalType = typename SFixed::InternalType; return SFixed::fromInternal(static_cast(left.getInternal() - right.getInternal())); } template< unsigned Integer, unsigned Fraction > constexpr SFixed operator *(const SFixed & left, const SFixed & right) { using InternalType = typename SFixed::InternalType; using PrecisionType = typename SFixed::InternalType; return SFixed::fromInternal(static_cast((static_cast(left.getInternal()) * static_cast(right.getInternal())) >> Fraction)); } template< unsigned Integer, unsigned Fraction > constexpr SFixed operator /(const SFixed & left, const SFixed & right) { using InternalType = typename SFixed::InternalType; using PrecisionType = typename SFixed::InternalType; return SFixed::fromInternal(static_cast((static_cast(left.getInternal()) << Fraction) / right.getInternal())); } // // Inter-size Arithmetic Operations // template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr auto operator +(const SFixed & left, const SFixed & right) -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) + static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr auto operator -(const SFixed & left, const SFixed & right) -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) - static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr auto operator *(const SFixed & left, const SFixed & right) -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) * static_cast(right)); } template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > constexpr auto operator /(const SFixed & left, const SFixed & right) -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > { using LeftType = SFixed; using RightType = SFixed; static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result"); using CompareType = FIXED_POINTS_DETAILS::LargerType; return (static_cast(left) / static_cast(right)); } // // Literal-type Operators // Generated by macro to make maintenance easier // #define LOGIC_OPERATOR( type, op )\ template< unsigned Integer, unsigned Fraction >\ constexpr bool operator op (const SFixed & left, const type & right)\ {\ return (left op SFixed(right));\ }\ \ template< unsigned Integer, unsigned Fraction >\ constexpr bool operator op (const type & left, const SFixed & right)\ {\ return (SFixed(left) op right);\ } #define ARITHMETIC_OPERATOR( type, op )\ template< unsigned Integer, unsigned Fraction >\ constexpr SFixed operator op (const SFixed & left, const type & right)\ {\ return (left op SFixed(right));\ }\ \ template< unsigned Integer, unsigned Fraction >\ constexpr SFixed operator op (const type & left, const SFixed & right)\ {\ return (SFixed(left) op right);\ } #define OPERATORS( opType, op ) \ opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteral, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralU, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralL, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralUL, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralLL, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::IntegerLiteralULL, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteral, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteralF, op )\ opType##_OPERATOR( FIXED_POINTS_DETAILS::DecimalLiteralL, op ) #define LOGIC_OPERATORS( op ) OPERATORS( LOGIC, op ) #define ARITHMETIC_OPERATORS( op ) OPERATORS( ARITHMETIC, op ) LOGIC_OPERATORS( == ) LOGIC_OPERATORS( != ) LOGIC_OPERATORS( < ) LOGIC_OPERATORS( > ) LOGIC_OPERATORS( <= ) LOGIC_OPERATORS( >= ) ARITHMETIC_OPERATORS( + ) ARITHMETIC_OPERATORS( - ) ARITHMETIC_OPERATORS( * ) ARITHMETIC_OPERATORS( / ) // Prevent Macro-bleed: #undef LOGIC_OPERATOR #undef ARITHMETIC_OPERATOR #undef OPERATORS #undef LOGIC_OPERATORS #undef ARITHMETIC_OPERATORS FIXED_POINTS_END_NAMESPACE