text: // Copyright 2017 Pharap
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  FIXED_POINTS_BEGIN_NAMESPACE
  
  //
  // multiply
  //
  
  template< unsigned Integer, unsigned Fraction >
  constexpr SFixed<Integer * 2, Fraction * 2> multiply(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	static_assert(((Integer + 1) * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize<intmax_t>::Value, "Multiplication cannot be performed, the result type would be too large");	
  
  	using ResultType = SFixed<Integer * 2, Fraction * 2>;
  	using InternalType = typename ResultType::InternalType;
  	return ResultType::fromInternal(static_cast<InternalType>(static_cast<InternalType>(left.getInternal()) * static_cast<InternalType>(right.getInternal())));
  }
  
  //
  // Basic Logic Operations
  //
  
  template< unsigned Integer, unsigned Fraction >
  constexpr bool operator ==(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	return (left.getInternal() == right.getInternal());
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr bool operator !=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	return (left.getInternal() != right.getInternal());
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr bool operator <(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	return (left.getInternal() < right.getInternal());
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr bool operator >(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	return (left.getInternal() > right.getInternal());
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr bool operator <=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	return (left.getInternal() <= right.getInternal());
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr bool operator >=(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	return (left.getInternal() >= right.getInternal());
  }
  
  //
  // Inter-size Logic Operations
  //
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr bool operator ==(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) == static_cast<CompareType>(right));
  }
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr bool operator !=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) != static_cast<CompareType>(right));
  }
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr bool operator <(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) < static_cast<CompareType>(right));
  }
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr bool operator >(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) > static_cast<CompareType>(right));
  }
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr bool operator <=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) <= static_cast<CompareType>(right));
  }
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr bool operator >=(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) >= static_cast<CompareType>(right));
  }
  
  //
  // Basic Arithmetic Operations
  //
  
  template< unsigned Integer, unsigned Fraction >
  constexpr SFixed<Integer, Fraction> operator +(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	using InternalType = typename SFixed<Integer, Fraction>::InternalType;
  	return SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>(left.getInternal() + right.getInternal()));
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr SFixed<Integer, Fraction> operator -(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	using InternalType = typename SFixed<Integer, Fraction>::InternalType;
  	return SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>(left.getInternal() - right.getInternal()));
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr SFixed<Integer, Fraction> operator *(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	static_assert(((Integer + 1) * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize<intmax_t>::Value, "Multiplication cannot be performed, the intermediary type would be too large");	
  	
  	using InternalType = typename SFixed<Integer, Fraction>::InternalType;
  	using PrecisionType = typename SFixed<Integer * 2, Fraction * 2>::InternalType;
          using SpeedType = typename SFixed< (Integer>>1), (Fraction>>1) >::InternalType;
          return (
              (static_cast<SpeedType>(left.getInternal()) == left.getInternal())
              &&
              (static_cast<SpeedType>(right.getInternal()) == right.getInternal())
              ) ?
              SFixed<Integer, Fraction>::fromInternal(left.getInternal() * right.getInternal() >> Fraction)
                  :
                  SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>((static_cast<PrecisionType>(left.getInternal()) * static_cast<PrecisionType>(right.getInternal())) >> Fraction))
              ;
  }
  
  template< unsigned Integer, unsigned Fraction >
  constexpr SFixed<Integer, Fraction> operator /(const SFixed<Integer, Fraction> & left, const SFixed<Integer, Fraction> & right)
  {
  	using InternalType = typename SFixed<Integer, Fraction>::InternalType;
  	using PrecisionType = typename SFixed<Integer * 2, Fraction * 2>::InternalType;
          return ( left.getInternal() << Fraction >> Fraction == left.getInternal() ) ?
              SFixed<Integer, Fraction>::fromInternal((left.getInternal()<<Fraction) / right.getInternal())
              :
              SFixed<Integer, Fraction>::fromInternal(static_cast<InternalType>((static_cast<PrecisionType>(left.getInternal()) << Fraction) / right.getInternal()));
  }
  
  //
  // Inter-size Arithmetic Operations
  //
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr auto operator +(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  	-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) + static_cast<CompareType>(right));
  }
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr auto operator -(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  	-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) - static_cast<CompareType>(right));
  }
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr auto operator *(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  	-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) * static_cast<CompareType>(right));
  }
  
  
  template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight >
  constexpr auto operator /(const SFixed<IntegerLeft, FractionLeft> & left, const SFixed<IntegerRight, FractionRight> & right)
  	-> FIXED_POINTS_DETAILS::LargerType< SFixed<IntegerLeft, FractionLeft>, SFixed<IntegerRight, FractionRight> >
  {
  	using LeftType = SFixed<IntegerLeft, FractionLeft>;
  	using RightType = SFixed<IntegerRight, FractionRight>;
  
  	static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result");
  	
  	using CompareType = FIXED_POINTS_DETAILS::LargerType<LeftType, RightType>;
  	
  	return (static_cast<CompareType>(left) / static_cast<CompareType>(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<Integer, Fraction> & left, const type & right)\
  	{\
  		return (left op SFixed<Integer, Fraction>(right));\
  	}\
  	\
  	template< unsigned Integer, unsigned Fraction >\
  	constexpr bool operator op (const type & left, const SFixed<Integer, Fraction> & right)\
  	{\
  		return (SFixed<Integer, Fraction>(left) op right);\
  	}
  
  #define ARITHMETIC_OPERATOR( type, op )\
  	template< unsigned Integer, unsigned Fraction >\
  	constexpr SFixed<Integer, Fraction> operator op (const SFixed<Integer, Fraction> & left, const type & right)\
  	{\
  		return (left op SFixed<Integer, Fraction>(right));\
  	}\
  	\
  	template< unsigned Integer, unsigned Fraction >\
  	constexpr SFixed<Integer, Fraction> operator op (const type & left, const SFixed<Integer, Fraction> & right)\
  	{\
  		return (SFixed<Integer, Fraction>(left) op right);\
  	}
  	
  #define OPERATORS( opType, op ) \
  	opType##_OPERATOR( char, op )\
  	opType##_OPERATOR( unsigned char, op )\
  	opType##_OPERATOR( signed char, op )\
  	opType##_OPERATOR( unsigned short int, op )\
  	opType##_OPERATOR( signed short int, op )\
  	opType##_OPERATOR( unsigned int, op )\
  	opType##_OPERATOR( signed int, op )\
  	opType##_OPERATOR( unsigned long int, op )\
  	opType##_OPERATOR( signed long int, op )\
  	opType##_OPERATOR( unsigned long long int, op )\
  	opType##_OPERATOR( signed long long int, op )\
  	opType##_OPERATOR( float, op )\
  	opType##_OPERATOR( double, op )\
  	opType##_OPERATOR( long double, 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( * ) // Edited by FManga
  ARITHMETIC_OPERATORS( / )
  
  // Edited by FManga
  template< unsigned Integer, unsigned Fraction, typename type >
      constexpr SFixed<Integer, Fraction> operator * (const SFixed<Integer, Fraction> & left, const type & right)
  {
      return SFixed<Integer, Fraction>::fromInternal(left.getInternal() * right);
  }
  template< unsigned Integer, unsigned Fraction, typename type >
      constexpr SFixed<Integer, Fraction> operator * (const type & left, const SFixed<Integer, Fraction> & right)
  {
      return SFixed<Integer, Fraction>::fromInternal(left * right.getInternal());
  }
  
  // Prevent Macro-bleed:
  
  #undef LOGIC_OPERATOR
  #undef ARITHMETIC_OPERATOR
  #undef OPERATORS
  #undef LOGIC_OPERATORS
  #undef ARITHMETIC_OPERATORS
  
  FIXED_POINTS_END_NAMESPACE
  