[Projekt] Fixpoint

Hier könnt ihr euch selbst, eure Homepage, euren Entwicklerstammtisch, Termine oder eure Projekte vorstellen.
Forumsregeln
Bitte Präfixe benutzen. Das Präfix "[Projekt]" bewirkt die Aufnahme von Bildern aus den Beiträgen des Themenerstellers in den Showroom. Alle Bilder aus dem Thema Showroom erscheinen ebenfalls im Showroom auf der Frontpage. Es werden nur Bilder berücksichtigt, die entweder mit dem attachement- oder dem img-BBCode im Beitrag angezeigt werden.

Die Bildersammelfunktion muss manuell ausgeführt werden, die URL dazu und weitere Details zum Showroom sind hier zu finden.

This forum is primarily intended for German-language video game developers. Please don't post promotional information targeted at end users.
Antworten
DerAlbi
Establishment
Beiträge: 269
Registriert: 20.05.2011, 05:37

[Projekt] Fixpoint

Beitrag von DerAlbi »

Hallo Leute,
ich bin mitlerweile so weit, dass meine Fixkomma-Lib mal der öffentlichen Kritik aussetzen möchte.
Also haut eure Compiler an, denkt euch wilde Formeln aus und guckt, welche Warnungen oder Fehler das Untier ausspuckt. Und ob das Ergebnis dem entspricht, was man sich wünscht!
Entwickelt unter GCC C++14.

Benutzung:

Code: Alles auswählen

#include "Fixpoint.hpp"
...
Fixpoint<22> a = 12.7;
Fixpoint<7, short> b = 6.35;
Fixpoint<35, long long> r = 3*a/b/1.5;
std::cout << "Fixpoint " << r.AsDouble() <<" all!"<< std::endl;
Fixpoint.hpp:

Code: Alles auswählen

#ifndef FIXPOINT_HPP
#define FIXPOINT_HPP

#include <algorithm>
#include <stdint.h>
#include <type_traits>
#include <assert.h>

/* Type by Size
 * the largest type in the system must also be its double-sized type
 * Example:
 * To indicate that there is no bigger type than SIntegerBySize<16>, give SIntegerBySize<32>
 * the same type as SIntegerBySize<16>
 */
template <int Size> struct SIntegerBySize {};
template <> struct SIntegerBySize<1> { using stype = int8_t;		using utype = uint8_t; };
template <> struct SIntegerBySize<2> { using stype = int16_t; 		using utype = uint16_t; };
template <> struct SIntegerBySize<4> { using stype = int32_t; 		using utype = uint32_t; };
template <> struct SIntegerBySize<8> { using stype = int64_t; 		using utype = uint64_t; };
#if defined(__SIZEOF_INT128__)
template <> struct SIntegerBySize<16>{ using stype = __int128; 		using utype = unsigned __int128; };
template <> struct SIntegerBySize<32>{ using stype = __int128; 		using utype = unsigned __int128; };
#else
template <> struct SIntegerBySize<16>{ using stype = int64_t; 		using utype = uint64_t; };
#endif

template <typename T> struct SDoubleWidth
{
	using type = typename std::conditional<std::is_signed<T>::value,
											typename SIntegerBySize<sizeof(T)*2>::stype,
											typename SIntegerBySize<sizeof(T)*2>::utype >::type;
};

template <typename T1, typename T2> struct SBiggerType
{ using type = typename std::conditional<(sizeof(T1)>sizeof(T2)) , T1, T2>::type; };

template<int X, int Y> struct static_min{ static constexpr int value = X < Y ? X : Y; };
template<int X, int Y> struct static_max{ static constexpr int value = X >= Y ? X : Y; };
template<int X, int min, int max> struct static_clamp{ static constexpr int value = static_max<static_min<X, max>::value, min>::value; };
template<int X> struct staitc_abs{ static constexpr int value = X < 0 ? -X : X; };
template<int X, typename T> struct static_shift{ static constexpr int value = static_clamp<X, 0, sizeof(T)*8-1>::value; };


template<int FP, typename T> struct Fixpoint;
template <int lhs_FP, typename lhs_T, int rhs_FP, typename rhs_T> struct ArbitraryMUL;
template <int lhs_FP, typename lhs_T, int rhs_FP, typename rhs_T> struct ArbitraryDIV;

template<typename ResultType, typename T> ResultType ShrinkType(const T& t)
{
	if (sizeof(T) > sizeof(ResultType))
	{
		constexpr int DestTypeSize = static_min<sizeof(ResultType)*8, sizeof(T)*8-1>::value;
		//constexpr int DiscardedBits = (sizeof(T) - sizeof(ResultType))*8;
		const bool __attribute__((unused)) OverflowCheck = (t >> DestTypeSize) == 0;
		assert(OverflowCheck);

		if (std::is_signed<ResultType>::value && std::is_signed<T>::value)
		{
			const bool InputIsNegative = t < 0;
			const bool CastedVersionIsNegative = ResultType(t) < 0;
			const bool __attribute__((unused)) SignHasChangedDueToOverflow = InputIsNegative == CastedVersionIsNegative;
			assert(SignHasChangedDueToOverflow);
		}
	}
	return ResultType(t);
}

/*
 * Quick overview:
 *
 * This Fixpoint library defines fixpoint via the type Fixpoint<Precision, UnderlyingType>. The underlying type is defaulted to int
 * while 'Precision' determines the number of fractional bits inside the Fixpoint.
 *
 * Example: Fixpoint<24>
 * Fixpoint<24> represents a layout such as "0x ii . ff ff ff" with i = integer bits and f = fractional bits in hexadecimal notation.
 * A Fixpoint<24> can therefore hold values like an 8-bit signed integer with 24 bits of fractional precision.
 *
 * Operations on Fixpoints are done in a lazy fashion. Meaning operand participants are only collected instead of evaluated directly.
 * This enables optimization in certain situations and avoids loss of precision or risk of overflow due to premature shift operations.
 * An operation is not executed before the return type precision is known.
 *
 * --- Left-Hand-Side-Rule ---
 * If the result of an operation is used in a bigger mathematical expression the operation will result in a Fixpoint type representing
 * the left-hand-side of the operation.
 *
 *  Example 1:
 *    			Fixpoint<12> result =  (Fixpoint<8>a + Fixpoint<16>b) * Fixpoint<16>c;
 *
 * will result in evaluating the (a+b) add-operation to its left-hand-side precision which is the precision of 'a' in the above
 * example. Then the multiplication-operand participant, namely (Fixpoint<8>("a+b") and Fixpoint<16>c, are collected and the
 * multiplication is executed due to the assignment to 'result' which tells the multiplication operation that a result with only
 * 12 bit precision is requested (while the original multiplication yields 24 bits of precision).
 * While the actual multiplication is not overflowing because its temporarily held in a double-sized type the conversion to the
 * result type may overflow. Its the same like long long = int * int is (in pseudocode) ok, but int = int * int can overflow.
 *
 * The left-hand-side rule is only a measure of last resort.
 *
 * Example 2:
 * 				Fixpoint<12> result = (Fixpoint<8>a * Fixpoint<16>b) + Fixpoint<16>c;
 *
 * The multiplication of a*b results in a Fixpoint<24, DoubleSizeType>("a*b") intermediate result. This result is then shifted to
 * fit inside the result precision. 'c' is also reduced to a precision of 12 before the actual addition is executed.
 *
 * The left-hand-side rule becomes weird in certain situations:
 *
 * Example 3:
 * 				Fixpoint<12> result = (Fixpoint<8>a * Fixpoint<16>b) + Fixpoint<16>c + Fixpoint<16>d + ...;
 *
 * Here the addition of Fixpoint<24, DoubleSizeType>("a*b") + Fixpoint<16>c has a left-hand-side type of Fixpoint<24, DoubleSizeType>
 * which propagates through the entire expression. Even there is no loss in precision or risk of overflow, it will not produce the best
 * assembler code.
 * 		TODO: 	One could collect the matching precision parameters first, so that left-hand-side dominance is avoided in that case.
 * 				Leading to  Fixpoint<24, DoubleSizeType>("a*b") + Fixpoint<16>("c+d") evaluation.
 *
 * It is important to inspect what you are doing (as always!). The problems in Example 3 could be avoided by rearranging the operands:
 *
 * Example 3, corrected:
 * 				Fixpoint<12> result = Fixpoint<16>c + (Fixpoint<8>a * Fixpoint<16>b) + Fixpoint<16>d;
 *
 * This will result in left-hand-side precision of 16 for the operation "c + (a*b)", therefore the last addition will be an
 * add-operation such as Fixpoint<16>(c + "a*b") + Fixpoint<16> d;
 * Since an Fixpoint<16> + Fixpoiint<16> operation is performed to be stored in a Fixpoint<12> the operation is performed at 16 bits
 * precision, then shifted down to 12 bit precision.
 * This may lead to overflow during Fixpoint<16>+Fixpoint<16> which would not occur if the addition is done as Fixpoint<12>+Fixpoint<12>.
 * However this behavior ensures that the LSB of the 12 bit result is precise. Live with it.
 *
 * The left-hand-side rule can be avoided by explicitly specifying the result precision of an operation:
 *
 * Example 4:
 * 				Fixpoint<24> result = Fixpoint<16>(Fixpoint<8>a * Fixpoint<16>b) + Fixpoint<16>c + Fixpoint<16>d;
 *                                    ~~~~~~~~~~~~
 *
 *
 * Integers are treated as Fixpoint<0> while float operands are converted to the same precision Fixpoint<lhs> as the left-hand-side is.
 * This ensures that no float arithmetic is done on the underlying type. (good for embedded)
 *
 * Example 5:
 * 				Fixpoint<24> result = Fixpoint<12>a * integer						results in
 * 				Fixpoint<24> result = Fixpoint<12>a * Fixpoint<0>(integer)  		which is of course:
 * 				Fixpoint<24> result = Fixpoint<12, DoubleSizedType>('a*integer');
 *
 * 				Fixpoint<24> result = Fixpoint<12>a * float							results in
 * 				Fixpoint<24> result = Fixpoint<12>a * Fixpoint<12>(float)  			which is of course:
 * 				Fixpoint<24> result = Fixpoint<24, DoubleSizedType>('a*float');
 *
 * 	In debug-Mode most overflows will assert().
 */

enum FixpointOperationAggregate{foaArbitraryADD, foaArbitraryMUL, foaArbitraryDIV};

template <int lhs_FP, typename lhs_T, int rhs_FP, typename rhs_T> struct ArbitraryADD
{
	ArbitraryADD(const lhs_T& _lhs, const rhs_T& _rhs): lhs(_lhs), rhs(_rhs) {}
	using type = ArbitraryADD<lhs_FP, lhs_T, rhs_FP, rhs_T>;
	static constexpr int lhs_prec = lhs_FP;
	static constexpr FixpointOperationAggregate Operation = foaArbitraryADD;
	using lhs_type = lhs_T;
	template<int ret_FP, typename ret_T> constexpr operator Fixpoint<ret_FP, ret_T>() const
	{
		if (ret_FP <= static_min<lhs_FP, rhs_FP>::value)  // return precision is the lowest
		{
			//Convert everything down to ret_FP, then add to allow overflow
			constexpr int minprec = static_min<lhs_FP, rhs_FP>::value;
			const lhs_T lhs_shifted = lhs >> staitc_abs<lhs_FP-minprec>::value;
			const rhs_T rhs_shifted = rhs >> staitc_abs<rhs_FP-minprec>::value;
			return Fixpoint<ret_FP, ret_T>::ConstructRaw( (lhs_shifted + rhs_shifted) >> staitc_abs<minprec-ret_FP>::value);
		}
		else if (ret_FP > static_max<lhs_FP, rhs_FP>::value) // return precision is the highest
		{
			//use the highest precision of lhs and rhs available,
			constexpr int max_lhs_rhs = static_max<lhs_FP, rhs_FP>::value;

			const lhs_T lhs_shifted = lhs_FP < max_lhs_rhs ? lhs << staitc_abs<lhs_FP-max_lhs_rhs>::value : lhs;
			const rhs_T rhs_shifted = rhs_FP < max_lhs_rhs ? rhs << static_clamp<staitc_abs<rhs_FP-max_lhs_rhs>::value, 0, sizeof(rhs_T)*8-1>::value : rhs;
			return Fixpoint<ret_FP, ret_T>::ConstructRaw((lhs_shifted + rhs_shifted) << staitc_abs<ret_FP-max_lhs_rhs>::value);
		} else if ( (rhs_FP >= ret_FP) && (ret_FP >= lhs_FP) )
		{
			const rhs_T rhs_shifted = rhs >> staitc_abs<rhs_FP-ret_FP>::value;
			const lhs_T lhs_shifted = lhs << staitc_abs<lhs_FP-ret_FP>::value;
			return Fixpoint<ret_FP, ret_T>::ConstructRaw(lhs_shifted + rhs_shifted);
		} else //if ( (lhs_FP >= ret_FP) && (ret_FP >= rhs_FP) )
		{
			const rhs_T rhs_shifted = rhs << staitc_abs<rhs_FP-ret_FP>::value;
			const lhs_T lhs_shifted = lhs >> staitc_abs<lhs_FP-ret_FP>::value;
			return Fixpoint<ret_FP, ret_T>::ConstructRaw(lhs_shifted + rhs_shifted);
		}
	}

	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	template<int ret_FP, typename ret_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, ret_FP, ret_T> operator + (const Fixpoint<ret_FP, ret_T>& _rhs) const
	{
		/* TODO: Discuss operand grouping to avoid LHS-Rule.
		 * Consider  Fixpoint<12>a + Fixpoint<10>b + Fixpoint<10>c;
		 * This is currently treated as  (Fixpoint<12>a + Fixpoint<10>b) + Fixpoint<10>c;  evaluating  Fixpoint<12>(a+b) + Fixpoint<10>c; due to LHS-Rule.
		 * Alternatively since its a lazy evaluation we can reorder the operands so that matching precision types are evaluated first in left to right order, then
		 * not-matching operands are treated with LHS-rule.
		 * Pro: less shifting
		 * Con: less predictable overflow behavior.
		 */
		return ArbitraryADD<lhs_FP, lhs_T, ret_FP, ret_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data, _rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T> operator + (const Arithmetic& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data,
																								  Fixpoint<std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename add_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, add_T::lhs_prec, typename add_T::lhs_type> operator + (const add_T& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, add_T::lhs_prec, typename add_T::lhs_type>( Fixpoint<lhs_FP, lhs_T>(*this).Data, Fixpoint<add_T::lhs_prec, typename add_T::lhs_type>(_rhs).Data);
	}

	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator + (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation(),
																								   Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation());
	}

	//Multiply-Add optimization
	template<int mullhs_FP, typename mullhs_T, int mulrhs_FP, typename mulrhs_T>
		inline constexpr ArbitraryADD<lhs_FP, lhs_T, mullhs_FP+mulrhs_FP, typename ArbitraryMUL<mullhs_FP, mullhs_T, mulrhs_FP, mulrhs_T>::DoubleSizeType>
		operator + (const ArbitraryMUL<mullhs_FP, mullhs_T, mulrhs_FP, mulrhs_T>& mul) const
	{
		const lhs_T rhs_shifted = ShrinkType<lhs_T>(lhs_FP > rhs_FP ? rhs << staitc_abs<lhs_FP-rhs_FP>::value : rhs >> staitc_abs<rhs_FP-lhs_FP>::value);
		return ArbitraryADD<lhs_FP, lhs_T, mullhs_FP+mulrhs_FP, typename ArbitraryMUL<mullhs_FP, mullhs_T, mulrhs_FP, mulrhs_T>::DoubleSizeType>(lhs+rhs_shifted, mul.Result());
	}

	// ----------------------------------------------------------------------------------------------------------------------------------------------------------------
	template<int ret_FP, typename ret_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, ret_FP, ret_T> operator - (const Fixpoint<ret_FP, ret_T>& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, ret_FP, ret_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data, -_rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T> operator - (const Arithmetic& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data,
					 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	  Fixpoint<std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(-_rhs).Data);
	}
	template<typename add_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, add_T::lhs_prec, typename add_T::lhs_type> operator - (const add_T& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, add_T::lhs_prec, typename add_T::lhs_type>( Fixpoint<lhs_FP, lhs_T>(*this).Data, -Fixpoint<add_T::lhs_prec, typename add_T::lhs_type>(_rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator - (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(-Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation(),
																								   Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation());
	}

	//Multiply-Add optimization
	template<int mullhs_FP, typename mullhs_T, int mulrhs_FP, typename mulrhs_T>
		inline constexpr ArbitraryADD<lhs_FP, lhs_T, mullhs_FP+mulrhs_FP, typename ArbitraryMUL<mullhs_FP, mullhs_T, mulrhs_FP, mulrhs_T>::DoubleSizeType>
		operator - (const ArbitraryMUL<mullhs_FP, mullhs_T, mulrhs_FP, mulrhs_T>& mul) const
	{
		const lhs_T rhs_shifted = lhs_FP > rhs_FP ? rhs << staitc_abs<lhs_FP-rhs_FP>::value : rhs >> staitc_abs<rhs_FP-lhs_FP>::value;
		return ArbitraryADD<lhs_FP, lhs_T, mullhs_FP+mulrhs_FP, typename ArbitraryMUL<mullhs_FP, mullhs_T, mulrhs_FP, mulrhs_T>::DoubleSizeType>(lhs+rhs_shifted, -mul.Result());
	}

	// ************************************************************************************************************
	template<int ret_FP, typename ret_T> inline constexpr ArbitraryMUL<lhs_FP, lhs_T, ret_FP, ret_T> operator * (const Fixpoint<ret_FP, ret_T>& _rhs) const
	{
		return ArbitraryMUL<lhs_FP, lhs_T, ret_FP, ret_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data, _rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T> operator * (const Arithmetic& _rhs) const
	{
		return ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data,
																								  Fixpoint<std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename mul_T> inline constexpr ArbitraryMUL<lhs_FP, lhs_T, mul_T::lhs_prec, typename mul_T::lhs_type> operator * (const mul_T& _rhs) const
	{
		return ArbitraryMUL<lhs_FP, lhs_T, mul_T::lhs_prec, typename mul_T::lhs_type>( Fixpoint<lhs_FP, lhs_T>(*this).Data, Fixpoint<mul_T::lhs_prec, typename mul_T::lhs_type>(_rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator * (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation(),
																								   Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation());
	}

	// ////////////////////////////////////////////////////////////////////////////////////////////////////////////

	template<int ret_FP, typename ret_T> inline constexpr ArbitraryDIV<lhs_FP, lhs_T, ret_FP, ret_T> operator / (const Fixpoint<ret_FP, ret_T>& _rhs) const
	{
		return ArbitraryMUL<lhs_FP, lhs_T, ret_FP, ret_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data, _rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr ArbitraryDIV<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T> operator / (const Arithmetic& _rhs) const
	{
		return ArbitraryDIV<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data,
																								  Fixpoint<std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename div_T> inline constexpr ArbitraryDIV<lhs_FP, lhs_T, div_T::lhs_prec, typename div_T::lhs_type> operator / (const div_T& _rhs) const
	{
		return ArbitraryDIV<lhs_FP, lhs_T, div_T::lhs_prec, typename div_T::lhs_type>( Fixpoint<lhs_FP, lhs_T>(*this).Data, Fixpoint<div_T::lhs_prec, typename div_T::lhs_type>(_rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryDIV<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator / (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryDIV<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation(),
																								   Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation());
	}
private:
	const lhs_T lhs;
	const rhs_T rhs;
};

//*****************************************************************************************************************************************************
//*****************************************************************************************************************************************************
//*****************************************************************************************************************************************************
template <int lhs_FP, typename lhs_T, int rhs_FP, typename rhs_T> struct ArbitraryMUL
{
	static constexpr int lhs_prec = lhs_FP;
	static constexpr FixpointOperationAggregate Operation = foaArbitraryMUL;
	using lhs_type = lhs_T;
	using DoubleSizeType = typename SDoubleWidth<typename SBiggerType<lhs_T, rhs_T>::type>::type;
	using type = ArbitraryMUL<lhs_FP, lhs_T, rhs_FP, rhs_T>;
	template<int, typename, int, typename> friend struct ArbitraryMUL;
	template<int, typename, int, typename> friend struct ArbitraryDIV;

 	inline ArbitraryMUL(const lhs_T& _lhs, const rhs_T& _rhs) : lhs(_lhs), rhs(_rhs) {}
	inline constexpr DoubleSizeType Result() const { return DoubleSizeType(lhs)*DoubleSizeType(rhs); }

	template<int ret_FP, typename ret_T> inline constexpr operator Fixpoint<ret_FP, ret_T>() const
	{
		constexpr int ResultShift = (lhs_FP + rhs_FP) - ret_FP;
		if (ResultShift >= 0) return Fixpoint<ret_FP, ret_T>::ConstructRaw(Result() >> staitc_abs<ResultShift>::value);
		else return Fixpoint<ret_FP, ret_T>::ConstructRaw(Result() << staitc_abs<ResultShift>::value);
	}

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	template<int add_FP, typename add_T> inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_FP, add_T> operator + (const Fixpoint<add_FP, add_T>& add) const
	{
		return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_FP, add_T>(Result(), add.Data);
	}

	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator + (const Arithmetic& _rhs) const
	{
		return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Result(),
																													 Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename add_T> inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_T::lhs_prec, typename add_T::lhs_type> operator + (const add_T& _rhs) const
	{
		return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_T::lhs_prec, typename add_T::lhs_type>( Result(), Fixpoint<add_T::lhs_prec, typename add_T::lhs_type>(_rhs).Data);
	}

	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator + (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation(),
																								   Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation());
	}

	// Multiply-Add optimization
	template <int madlhs_FP, typename madlhs_T, int madrhs_FP, typename madrhs_T>
		inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, madlhs_FP+madrhs_FP, typename ArbitraryMUL<madlhs_FP, madlhs_T, madrhs_FP, madrhs_T>::DoubleSizeType>
			operator + (const ArbitraryMUL<madlhs_FP, madlhs_T, madrhs_FP, madrhs_T>& _rhs) const
	{
		return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, madlhs_FP+madrhs_FP, typename ArbitraryMUL<madlhs_FP, madlhs_T, madrhs_FP, madrhs_T>::DoubleSizeType>(Result(), _rhs.Result());
	}

	//---------------------------------------------------------------------------------------------------------------------------------------------------------------
	template<int add_FP, typename add_T> inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_FP, add_T> operator - (const Fixpoint<add_FP, add_T>& _rhs) const
	{
		return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_FP, add_T>(Result(), -_rhs.Data);
	}

	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator - (const Arithmetic & _rhs) const
	{
			 return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Result(), -Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename add_T> inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_T::lhs_prec, typename add_T::lhs_type> operator - (const add_T& _rhs) const
	{
		return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, add_T::lhs_prec, typename add_T::lhs_type>( Result(), -Fixpoint<add_T::lhs_prec, typename add_T::lhs_type>(_rhs).Data);
	}

	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator - (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(-Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation(),
																								    Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation());
	}
	// Multiply-Add optimization
	template <int madlhs_FP, typename madlhs_T, int madrhs_FP, typename madrhs_T>
		inline constexpr ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, madlhs_FP+madrhs_FP, typename ArbitraryMUL<madlhs_FP, madlhs_T, madrhs_FP, madrhs_T>::DoubleSizeType>
			operator - (const ArbitraryMUL<madlhs_FP, madlhs_T, madrhs_FP, madrhs_T>& add) const
	{
		return ArbitraryADD<lhs_FP + rhs_FP, DoubleSizeType, madlhs_FP+madrhs_FP, typename ArbitraryMUL<madlhs_FP, madlhs_T, madrhs_FP, madrhs_T>::DoubleSizeType>(Result(), -add.Result());
	}

	// ***************************************************************************************************************************************************************
	template<int ret_FP, typename ret_T> inline constexpr ArbitraryMUL<lhs_FP, lhs_T, ret_FP, ret_T> operator * (const Fixpoint<ret_FP, ret_T>& _rhs) const
	{
		return ArbitraryMUL<lhs_FP, lhs_T, ret_FP, ret_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data, _rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T> operator * (const Arithmetic& _rhs) const
	{
		return ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data,
																								   Fixpoint<std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename mul_T> inline constexpr ArbitraryMUL<lhs_FP, lhs_T, mul_T::lhs_prec, typename mul_T::lhs_type> operator * (const mul_T& _rhs) const
	{
		return ArbitraryMUL<lhs_FP, lhs_T, mul_T::lhs_prec, typename mul_T::lhs_type>(Fixpoint<lhs_FP, lhs_T>(*this).Data, Fixpoint<mul_T::lhs_prec, typename mul_T::lhs_type>(_rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator * (const Arithmetic& lhs, const type& rhs)
	{
		return ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation(),
																								    Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation());
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	template<int ret_FP, typename ret_T> inline constexpr ArbitraryDIV<lhs_FP+rhs_FP, DoubleSizeType, ret_FP, ret_T> operator / (const Fixpoint<ret_FP, ret_T>& _rhs) const
	{
		return ArbitraryDIV<lhs_FP+rhs_FP, DoubleSizeType, ret_FP, ret_T>(Result(), _rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr ArbitraryDIV<lhs_FP+rhs_FP, DoubleSizeType, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T> operator / (const Arithmetic& _rhs) const
	{
		return ArbitraryDIV<lhs_FP+rhs_FP, DoubleSizeType, std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(Result(),
																								  	  	  	  	   Fixpoint<std::is_integral<Arithmetic>::value ? 0: lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename div_T> inline constexpr ArbitraryDIV<lhs_FP+rhs_FP, DoubleSizeType, div_T::lhs_prec, typename div_T::lhs_type> operator / (const div_T& _rhs) const
	{
		return ArbitraryDIV<lhs_FP+rhs_FP, DoubleSizeType, div_T::lhs_prec, typename div_T::lhs_type>(Result(), Fixpoint<div_T::lhs_prec, typename div_T::lhs_type>(_rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryDIV<lhs_FP, lhs_T, lhs_FP, lhs_T> operator / (const Arithmetic& lhs, const type& rhs)
	{
		//TODO check not involving DoubleSizedType. its an annomaly i cant resolve right now
		return ArbitraryDIV<lhs_FP, lhs_T, lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(lhs).InternalRepresentation(),
														 Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation() );
	}
private:
	const lhs_T lhs;
	const rhs_T rhs;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <int lhs_FP, typename lhs_T, int rhs_FP, typename rhs_T> struct ArbitraryDIV
{
	static constexpr int lhs_prec = lhs_FP;
	static constexpr FixpointOperationAggregate Operation = foaArbitraryDIV;
	using lhs_type = lhs_T;

	using DoubleSizeType = typename SDoubleWidth<lhs_T>::type;
	using type = ArbitraryDIV<lhs_FP, lhs_T, rhs_FP, rhs_T>;
	template<int, typename, int, typename> friend struct ArbitraryDIV;
	template<int, typename, int, typename> friend struct ArbitraryMUL;
	template<int, typename, int, typename> friend struct ArbitraryADD;
	template<int, typename> friend struct Fixpoint;
	inline ArbitraryDIV(const lhs_T& _lhs, const rhs_T& _rhs) : lhs(_lhs), rhs(_rhs) {}

	template<int ret_FP, typename ret_T> inline constexpr operator Fixpoint<ret_FP, ret_T>() const
	{
		constexpr int result_prec = lhs_FP - rhs_FP;
		(volatile void)result_prec;
		if (sizeof(lhs_T) < sizeof(rhs_T))
		{
			if (result_prec < ret_FP)
			{
				if (lhs_FP > rhs_FP)
				{
					const DoubleSizeType lhs_shift = DoubleSizeType(lhs) << static_clamp<ret_FP - result_prec, 0, sizeof(DoubleSizeType)*8-1>::value;
					return Fixpoint<ret_FP, ret_T>::ConstructRaw(lhs_shift / rhs);
				}
				else
				{
					using dst = typename SDoubleWidth<typename SBiggerType<lhs_T, ret_T>::type>::type;
					constexpr int possiblePrec = ((int)sizeof(rhs_T)-(int)sizeof(lhs_T))*8;
					constexpr int rhs_correct = ret_FP - result_prec - possiblePrec;
					const rhs_T rhs_shift = rhs_correct > 0 ? rhs >> static_shift<rhs_correct, rhs_T>::value :
															  rhs << static_shift<-rhs_correct,rhs_T>::value;

					constexpr unsigned int ActualLeftShift = static_min<(sizeof(dst)-sizeof(lhs))*8, possiblePrec>::value;
					constexpr unsigned int NeededRightShift = possiblePrec-ActualLeftShift;
					const dst lhs_shift = dst(lhs) << staitc_abs<ActualLeftShift>::value;
					return Fixpoint<ret_FP, ret_T>::ConstructRaw( lhs_shift / (rhs_shift >> staitc_abs<NeededRightShift>::value) );
				}
			}
			else
			{
				/*if (lhs_FP >= rhs_FP) */return Fixpoint<ret_FP, ret_T>::ConstructRaw( (lhs / rhs) >> static_shift<result_prec-ret_FP, lhs_T>::value);
				//else return Fixpoint<ret_FP, ret_T>::ConstructRaw( 0 );   // impossible
			}
		}
		else
		{
			if (result_prec < ret_FP)
			{
				//
				constexpr bool ExpandToDoubleSize = int(sizeof(lhs) - sizeof(rhs)) < int(sizeof(ret_T));
				if (ExpandToDoubleSize)
				{
					const DoubleSizeType lhs_shift = DoubleSizeType(lhs) << static_shift<ret_FP-result_prec, DoubleSizeType>::value;
					return Fixpoint<ret_FP, ret_T>::ConstructRaw(lhs_shift / rhs);
				}
				else
				{
					/* Result type is smaller(or equal) than a / b naturally gives.
					 * Example: short = long long / int.
					 * This means, the lhs-shift may overflow here.
					 * This problem only goes unnoticed in conditions like: int = long long / int
					 */
					return Fixpoint<ret_FP, ret_T>::ConstructRaw((lhs<<static_shift<ret_FP-result_prec, lhs_T>::value) / rhs);
				}
			} else return Fixpoint<ret_FP, ret_T>::ConstructRaw( (lhs / rhs) >> static_shift<result_prec-ret_FP, DoubleSizeType>::value );
		}
	}
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	template<int sub_FP, typename sub_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, sub_FP, sub_T> operator + (const Fixpoint<sub_FP, sub_T>& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, sub_FP, sub_T>( Fixpoint<lhs_FP, lhs_T>(*this).Data, _rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator + (const Arithmetic& _rhs)
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data, Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename add_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, add_T::lhs_prec, typename add_T::lhs_type> operator + (const add_T& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, add_T::lhs_prec, typename add_T::lhs_type>( Fixpoint<lhs_FP, lhs_T>(*this).Data, +Fixpoint<add_T::lhs_prec, typename add_T::lhs_type>(_rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<lhs_FP, lhs_T, lhs_FP, lhs_T> operator + (Arithmetic _lhs, const type& _rhs)
	{
		return ArbitraryADD<lhs_FP, lhs_T, lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(_lhs).InternalRepresentation(),
														 Fixpoint<lhs_FP, lhs_T>(_rhs).InternalRepresentation());
	}

	// ------------------------------------------------------------------------------------------------------------
	template<int sub_FP, typename sub_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, sub_FP, sub_T> operator - (const Fixpoint<sub_FP, sub_T>& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, sub_FP, sub_T>( Fixpoint<lhs_FP, lhs_T>(*this).Data, -_rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T> operator - (const Arithmetic& _rhs)
	{
		return ArbitraryADD<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(Fixpoint<lhs_FP, lhs_T>(*this).Data, -Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(_rhs).Data);
	}
	template<typename sub_T> inline constexpr ArbitraryADD<lhs_FP, lhs_T, sub_T::lhs_prec, typename sub_T::lhs_type> operator - (const sub_T& _rhs) const
	{
		return ArbitraryADD<lhs_FP, lhs_T, sub_T::lhs_prec, typename sub_T::lhs_type>( Fixpoint<lhs_FP, lhs_T>(*this).Data, -Fixpoint<sub_T::lhs_prec, typename sub_T::lhs_type>(_rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T, lhs_FP, lhs_T> operator - (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryADD<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T, lhs_FP, lhs_T>(Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation(),
														 	 	 	 	 	 	 	 	 	 	   -Fixpoint<lhs_FP, lhs_T>(rhs).InternalRepresentation());
	}


	// ************************************************************************************************************
	template<int mul_FP, typename mul_T> inline constexpr ArbitraryDIV<lhs_FP+mul_FP, DoubleSizeType, rhs_FP, rhs_T> operator * (const Fixpoint<mul_FP, mul_T>& _rhs) const
	{
		static_assert(sizeof(lhs_T) < sizeof(typename SDoubleWidth<lhs_T>::type), "This construct sadly is undefined due to operand optimization. (a/b)*c * d becomes (a*c)/b * d to avoid shifting of a during division. Please consider (a/b)*(c*d) or Fixpoint<LeftSidePrecision>(a/b*c)*d");
		return ArbitraryDIV<lhs_FP+mul_FP, DoubleSizeType, rhs_FP, rhs_T>(ArbitraryMUL<lhs_FP, lhs_T, mul_FP, mul_T>(lhs, _rhs.Data).Result(), rhs);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryDIV<lhs_FP + (std::is_integral<Arithmetic>::value ? 0 : lhs_FP), DoubleSizeType, rhs_FP, rhs_T> operator * (const Arithmetic& mul)
	{
		return ArbitraryDIV<lhs_FP + (std::is_integral<Arithmetic>::value ? 0 : lhs_FP), DoubleSizeType, rhs_FP, rhs_T>(
					ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs,
																										Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(mul).InternalRepresentation()).Result(),
					rhs);
	}
	template<typename mul_T> inline constexpr ArbitraryDIV<lhs_FP+mul_T::lhs_prec, DoubleSizeType, rhs_FP, rhs_T> operator * (const mul_T& _rhs) const
	{
		static_assert(sizeof(lhs_T) < sizeof(typename SDoubleWidth<lhs_T>::type), "This construct sadly is undefined due to operand optimization. (a/b)*c * d becomes (a*c)/b * d to avoid shifting of a during division. Please consider (a/b)*(c*d) or Fixpoint<LeftSidePrecision>(a/b*c)*d");
		return (*this) * Fixpoint< mul_T::lhs_prec, typename mul_T::lhs_type>(_rhs);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryDIV<lhs_FP + (std::is_integral<Arithmetic>::value ? 0 : lhs_FP), DoubleSizeType, rhs_FP, rhs_T> operator * (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryDIV<lhs_FP + (std::is_integral<Arithmetic>::value ? 0 : lhs_FP), DoubleSizeType, rhs_FP, rhs_T>(
					ArbitraryMUL<lhs_FP, lhs_T, std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(rhs.lhs,
																										Fixpoint<std::is_integral<Arithmetic>::value ? 0 : lhs_FP, lhs_T>(lhs).InternalRepresentation()).Result(),
					rhs.rhs);
	}

	// ////////////////////////////////////////////////////////////////////////////////////////////////////////////

	template<int div_FP, typename div_T> inline constexpr ArbitraryDIV<lhs_FP, lhs_T, div_FP+rhs_FP, typename ArbitraryMUL<rhs_FP, rhs_T, div_FP, div_T>::DoubleSizeType> operator / (const Fixpoint<div_FP, div_T>& _rhs) const
	{
		static_assert(sizeof(rhs_T) < sizeof(typename SDoubleWidth<rhs_T>::type), "Sadly this construct is undefined due to operand optimization. Constructs like (a/b)/c/d  become a/(b*c) / d. Please consider a/(b*c*d) directly or Fixpoint<LeftSidePrecision>(a/b/c) / d");
		return ArbitraryDIV<lhs_FP, lhs_T, div_FP+rhs_FP, typename ArbitraryMUL<rhs_FP, rhs_T, div_FP, div_T>::DoubleSizeType>(lhs, ArbitraryMUL<rhs_FP, rhs_T, div_FP, div_T>(rhs, _rhs.Data).Result());
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryDIV<rhs_FP + (std::is_integral<Arithmetic>::value ? 0 : rhs_FP), DoubleSizeType, lhs_FP, lhs_T> operator / (Arithmetic _lhs, const type& _rhs)
	{
		return ArbitraryDIV<rhs_FP + (std::is_integral<Arithmetic>::value ? 0 : rhs_FP), DoubleSizeType, lhs_FP, lhs_T>(
					ArbitraryMUL<rhs_FP, rhs_T, std::is_integral<Arithmetic>::value ? 0 : rhs_FP, rhs_T>(_rhs.rhs,
																										Fixpoint<std::is_integral<Arithmetic>::value ? 0 : rhs_FP, rhs_T>(_lhs).InternalRepresentation()).Result(),
					_rhs.lhs);
	}
	template<typename div_T, typename = typename std::enable_if<div_T::Operation != foaArbitraryDIV>::type> inline constexpr ArbitraryDIV<lhs_FP, lhs_T, rhs_FP+div_T::lhs_prec, DoubleSizeType> operator / (const div_T& _rhs) const
	{
		static_assert(sizeof(rhs_T) < sizeof(typename SDoubleWidth<rhs_T>::type), "Sadly this construct is undefined due to operand optimization. Constructs like (a/b)/c/d  become a/(b*c) / d. Please consider a/(b*c*d) directly or Fixpoint<LeftSidePrecision>(a/b/c) / d");
		return (*this) / Fixpoint< div_T::lhs_prec, typename div_T::lhs_type>(_rhs);
	}
	template<int div_lhs_FP, typename div_lhs_T, int div_rhs_FP, typename div_rhs_T> inline constexpr ArbitraryDIV<lhs_FP+div_rhs_FP, typename ArbitraryMUL<lhs_FP, lhs_T, div_rhs_FP, div_rhs_T>::DoubleSizeType,
																												   rhs_FP+div_lhs_FP, typename ArbitraryMUL<rhs_FP, rhs_T, div_lhs_FP, div_lhs_T>::DoubleSizeType> operator / (const ArbitraryDIV<div_lhs_FP, div_lhs_T, div_rhs_FP, div_rhs_T>& _rhs) const
	{
		constexpr int newlhs_size = sizeof(typename ArbitraryMUL<lhs_FP, lhs_T, div_rhs_FP, div_rhs_T>::DoubleSizeType);
		constexpr int newrhs_size = sizeof(typename ArbitraryMUL<rhs_FP, rhs_T, div_lhs_FP, div_lhs_T>::DoubleSizeType);
		static_assert( !(newlhs_size < (sizeof(lhs_T)+sizeof(div_rhs_T))) || (newrhs_size < (sizeof(rhs_T)+sizeof(div_lhs_T))),
				"Sadly this construct is undefined due to operand optimization. (a/b) / (c/d) becomes (a*d)/(b*c). If either a*d or b*c does not fit into a type you see this error. This can happen if (a/b) is already an optimized expression like (a/b/x) which became a/(b*x)");
		return ArbitraryDIV<lhs_FP+div_rhs_FP, typename ArbitraryMUL<lhs_FP, lhs_T, div_rhs_FP, div_rhs_T>::DoubleSizeType,
							rhs_FP+div_lhs_FP, typename ArbitraryMUL<rhs_FP, rhs_T, div_lhs_FP, div_lhs_T>::DoubleSizeType>(ArbitraryMUL<lhs_FP, lhs_T, div_rhs_FP, div_rhs_T>(lhs, _rhs.rhs).Result(),
																															ArbitraryMUL<rhs_FP, rhs_T, div_lhs_FP, div_lhs_T>(rhs, _rhs.lhs).Result() );
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		 inline constexpr ArbitraryDIV<lhs_FP, lhs_T, rhs_FP + (std::is_integral<Arithmetic>::value ? 0 : rhs_FP), typename ArbitraryMUL<rhs_FP, rhs_T, std::is_integral<Arithmetic>::value ? 0 : rhs_FP, rhs_T>::DoubleSizeType> operator / (const Arithmetic& div)
	{
		static_assert(sizeof(rhs_T) < sizeof(typename ArbitraryMUL<rhs_FP, rhs_T, std::is_integral<Arithmetic>::value ? 0 : rhs_FP, rhs_T>::DoubleSizeType),
				"Sadly this construct is undefined due to operand optimization. Constructs like (a/b)/c/d  become a/(b*c) / d. Please consider a/(b*c*d) directly or Fixpoint<Precision(, Type)>(a/b/c) / d");
		return ArbitraryDIV<lhs_FP, lhs_T, rhs_FP + (std::is_integral<Arithmetic>::value ? 0 : rhs_FP), typename ArbitraryMUL<rhs_FP, rhs_T, std::is_integral<Arithmetic>::value ? 0 : rhs_FP, rhs_T>::DoubleSizeType>(lhs,
																											     ArbitraryMUL<rhs_FP, rhs_T, std::is_integral<Arithmetic>::value ? 0 : rhs_FP, rhs_T>(rhs,
																																						  	  	  	  	  	  	  	  	  	  	  	  Fixpoint<std::is_integral<Arithmetic>::value ? 0 : rhs_FP, rhs_T>(div).InternalRepresentation()).Result());
	}
private:
	const lhs_T lhs;
	const rhs_T rhs;
};


template<int FP, typename T = int> struct Fixpoint
{
	static_assert(FP >= 0, "Negative precision requested - should this mybe allowed ?? It makes sense.");
	static_assert(sizeof(T)*8 > FP, "Storage type does not have sufficient number bits for your requested precision");
	static_assert( std::is_signed<T>::value ? (sizeof(T)*8-1) != FP : true, "Requested precision makes value 1.0 overwrite the sign bit of the underlying type. Try an unsigned type for reduce precision");

	static constexpr T One = T(1u)<<T(FP);
	static constexpr T Precission = FP;
	using StorageType = T;
	using type = Fixpoint<FP, T>;
	using DoubleSizeType = typename SDoubleWidth<T>::type;
	template<int, typename> friend struct Fixpoint;
	template<int, typename, int, typename> friend struct ArbitraryADD;
	template<int, typename, int, typename> friend struct ArbitraryMUL;
	template<int, typename, int, typename> friend struct ArbitraryDIV;

	Fixpoint(): Data(0) {};
	inline Fixpoint(const type& t): Data(t.Data) { }
	template<typename InitType, typename = typename std::enable_if<std::is_arithmetic<InitType>::value>::type > inline Fixpoint(const InitType& t): Data(T(t*One)) {};

	template<int rhs_FP, typename rhs_T> inline constexpr Fixpoint(const Fixpoint<rhs_FP, rhs_T>& rhs)
	{
		if (FP > rhs_FP) Data = rhs.Data << staitc_abs<rhs_FP-FP>::value;
		else Data = rhs.Data >> staitc_abs<rhs_FP-FP>::value;
	}
	// =================================================================================================================================================
	template<int rhs_FP, typename rhs_T> inline constexpr type& operator=(const Fixpoint<rhs_FP, rhs_T>& rhs)
	{
		if (FP > rhs_FP) Data = rhs.Data << staitc_abs<rhs_FP-FP>::value;
		else Data = rhs.Data >> staitc_abs<rhs_FP-FP>::value;
		return *this;
	}


	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	template<int rhs_FP, typename rhs_T> inline constexpr ArbitraryADD<FP, T, rhs_FP, rhs_T> operator + (const Fixpoint<rhs_FP, rhs_T>& rhs) const
	{
		return ArbitraryADD<FP, T, rhs_FP, rhs_T>(Data, rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T> operator + (const Arithmetic & rhs) const
	{
		return ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T>(Data, Fixpoint<std::is_integral<Arithmetic>::value ? 0: FP, T>(rhs).Data);
	}
	template<typename add_T> inline constexpr ArbitraryADD<FP, T, add_T::lhs_prec, typename add_T::lhs_type> operator + (const add_T& rhs) const
	{
		return ArbitraryADD<FP, T, add_T::lhs_prec, typename add_T::lhs_type>(Data, Fixpoint<add_T::lhs_prec, typename add_T::lhs_type>(rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0 : FP, T> operator +(Arithmetic lhs, const type& rhs)
	{
		return ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0 : FP, T>(rhs.InternalRepresentation(), Fixpoint<std::is_integral<Arithmetic>::value ? 0 : FP, T>(lhs).InternalRepresentation());
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------
	template<int rhs_FP, typename rhs_T> inline constexpr ArbitraryADD<FP, T, rhs_FP, rhs_T> operator - (const Fixpoint<rhs_FP, rhs_T>& rhs) const
	{
		return ArbitraryADD<FP, T, rhs_FP, rhs_T>(Data, -rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T> operator - (const Arithmetic & rhs) const
	{
		return ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T>(Data, -Fixpoint<std::is_integral<Arithmetic>::value ? 0: FP, T>(rhs).Data);
	}
	template<typename add_T> inline constexpr ArbitraryADD<FP, T, add_T::lhs_prec, typename add_T::lhs_type> operator - (const add_T& rhs) const
	{
		return ArbitraryADD<FP, T, add_T::lhs_prec, typename add_T::lhs_type>(Data, -Fixpoint<add_T::lhs_prec, typename add_T::lhs_type>(rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0 : FP, T> operator -(Arithmetic lhs, const type& rhs)
	{
		return ArbitraryADD<FP, T, std::is_integral<Arithmetic>::value ? 0 : FP, T>(-rhs.InternalRepresentation(),
																				    Fixpoint<std::is_integral<Arithmetic>::value ? 0 : FP, T>(lhs).InternalRepresentation());
	}

	//***************************************************************************************************************************************************
	template<int rhs_FP, typename rhs_T> inline constexpr ArbitraryMUL<FP, T, rhs_FP, rhs_T> operator * (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{
		return ArbitraryMUL<FP, T, rhs_FP, rhs_T>(Data, rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryMUL<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T> operator * (const Arithmetic & rhs) const
	{
		return ArbitraryMUL<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T>(Data, Fixpoint<std::is_integral<Arithmetic>::value ? 0: FP, T>(rhs).Data);
	}
	template<typename mul_T> inline constexpr ArbitraryMUL<FP, T, mul_T::lhs_prec, typename mul_T::lhs_type> operator * (const mul_T& rhs) const
	{
		return ArbitraryMUL<FP, T, mul_T::lhs_prec, typename mul_T::lhs_type>(Data, Fixpoint<mul_T::lhs_prec, typename mul_T::lhs_type>(rhs).Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryMUL<FP, T, std::is_integral<Arithmetic>::value ? 0 : FP, T> operator *(Arithmetic lhs, const type& rhs)
	{
		return ArbitraryMUL<FP, T, std::is_integral<Arithmetic>::value ? 0 : FP, T>(rhs.InternalRepresentation(),
																				   Fixpoint<std::is_integral<Arithmetic>::value ? 0 : FP, T>(lhs).InternalRepresentation());
	}

	// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	template<int rhs_FP, typename rhs_T> inline constexpr ArbitraryDIV<FP, T, rhs_FP, rhs_T> operator / (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{
		return ArbitraryDIV<FP, T, rhs_FP, rhs_T>(Data, rhs.Data);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		inline constexpr ArbitraryDIV<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T> operator / (const Arithmetic & rhs) const
	{
		return ArbitraryDIV<FP, T, std::is_integral<Arithmetic>::value ? 0: FP, T>(Data, Fixpoint<std::is_integral<Arithmetic>::value ? 0: FP, T>(rhs).Data);
	}
	template<typename div_T> inline constexpr ArbitraryDIV<FP, T, div_T::lhs_prec, typename div_T::lhs_type> operator / (const div_T& rhs) const
	{
		static_assert( sizeof(typename div_T::lhs_type) < sizeof(DoubleSizeType), "Sadly this construct is undefined due to operand optimization. a/(b/c/d) becomes a/[(b*d)/c]. Try a/Fixpoint<LeftSidePrecision>(b/c/d)");
		return ArbitraryDIV<FP, T, div_T::lhs_prec, typename div_T::lhs_type>(Data, Fixpoint<div_T::lhs_prec, typename div_T::lhs_type>(rhs).Data);
	}

	template<int divrhs_FP, typename divrhs_T, int divlhs_FP, typename divlhs_T, typename = typename std::enable_if<static_max<sizeof(divlhs_T), sizeof(divrhs_T)>::value < sizeof(DoubleSizeType)>::type >
		inline constexpr ArbitraryDIV<FP+divrhs_FP, DoubleSizeType, divlhs_FP, divlhs_T> operator / (const ArbitraryDIV<divlhs_FP, divlhs_T, divrhs_FP, divrhs_T> & div) const
	{
		return ArbitraryDIV<FP+divrhs_FP, DoubleSizeType, divlhs_FP, divlhs_T> //divrhs_T prüfen
				( ArbitraryMUL<FP, T, divlhs_FP, divlhs_T>(Data, div.rhs).Result(), div.lhs);
	}
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr ArbitraryDIV<std::is_integral<Arithmetic>::value ? 0 : FP, T, FP, T> operator / (Arithmetic lhs, const type& rhs)
	{
		return ArbitraryDIV<std::is_integral<Arithmetic>::value ? 0 : FP, T, FP, T>(Fixpoint<std::is_integral<Arithmetic>::value ? 0 : FP, T>(lhs).InternalRepresentation(), rhs.InternalRepresentation());
	}


	template<typename rhs_T> Fixpoint& operator += (const rhs_T& rhs)
	{ *this = *this + rhs; return *this; }
	template<typename rhs_T> Fixpoint& operator -= (const rhs_T& rhs)
	{ *this = *this - rhs; return *this; }
	template<typename rhs_T> Fixpoint& operator *= (const rhs_T& rhs)
	{ *this = *this * rhs; return *this; }
	template<typename rhs_T> Fixpoint& operator /= (const rhs_T& rhs)
	{ *this = *this / rhs; return *this; }

	constexpr inline Fixpoint operator >> (const int& rhs) const
	{ return Fixpoint::ConstructRaw(Data >> rhs); }
	constexpr inline Fixpoint operator << (const int& rhs) const
	{ return Fixpoint::ConstructRaw(Data << rhs); }

	Fixpoint& operator >>= (const int& rhs)
	{ Data >>= rhs; return *this; }
	Fixpoint& operator <<= (const int& rhs)
	{ Data <<= rhs; return *this; }

	template<int rhs_FP, typename rhs_T> inline constexpr bool operator == (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{ Fixpoint tmp = rhs; return Data == tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr bool operator == (const Arithmetic& rhs) const
	{ Fixpoint tmp = rhs; return Data == tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr bool operator == (Arithmetic lhs, const type& rhs)
	{ return rhs == lhs; }

	template<int rhs_FP, typename rhs_T> inline constexpr bool operator != (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{ Fixpoint tmp = rhs; return Data != tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr bool operator != (const Arithmetic& rhs) const
	{ Fixpoint tmp = rhs; return Data != tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr bool operator != (Arithmetic lhs, const type& rhs)
	{ return rhs != lhs; }

	template<int rhs_FP, typename rhs_T> inline constexpr bool operator < (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{ Fixpoint tmp = rhs; return Data < tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr bool operator < (const Arithmetic& rhs) const
	{ Fixpoint tmp = rhs; return Data < tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr bool operator < (Arithmetic lhs, const type& rhs)
	{ return rhs > lhs; }

	template<int rhs_FP, typename rhs_T> inline constexpr bool operator > (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{ Fixpoint tmp = rhs; return Data > tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr bool operator > (const Arithmetic& rhs) const
	{ Fixpoint tmp = rhs; return Data > tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr bool operator > (Arithmetic lhs, const type& rhs)
	{ return rhs < lhs; }

	template<int rhs_FP, typename rhs_T> inline constexpr bool operator <= (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{ Fixpoint tmp = rhs; return Data <= tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type>
		inline constexpr bool operator <= (const Arithmetic& rhs) const
	{ Fixpoint tmp = rhs; return Data <= tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr bool operator <= (Arithmetic lhs, const type& rhs)
	{ return rhs >= lhs; }

	template<int rhs_FP, typename rhs_T> inline constexpr bool operator >= (const Fixpoint<rhs_FP, rhs_T> & rhs) const
	{ Fixpoint tmp = rhs; return Data >= tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type> inline constexpr bool operator >= (const Arithmetic& rhs) const
	{ Fixpoint tmp = rhs; return Data >= tmp.Data; }
	template<typename Arithmetic, typename = typename std::enable_if<std::is_arithmetic<Arithmetic>::value>::type >
		friend inline constexpr bool operator >= (Arithmetic lhs, const type& rhs)
	{ return rhs <= lhs; }

	constexpr T InternalRepresentation() const { return Data; }




	inline constexpr float AsFloat() { return float(Data)/float(One); }
	inline constexpr double AsDouble() { return double(Data)/double(One); }
	inline constexpr T IntegerPart() { return Data >> FP; }
	inline constexpr Fixpoint FractionalPart() { return ConstructRaw(Data & ((T(1)<<FP)-1)); }
private:
	T Data;
	template<typename Input_t> static inline Fixpoint<FP, T> ConstructRaw(const Input_t& Data)
	{
		Fixpoint<FP, T> retval;
		retval.Data = ShrinkType<T>(Data);
		return retval;
	}
};

#endif
Manche Überläufe werden zur Laufzeit gecheckt. Das verhindert ne Menge Optimierung. Also zur Not als Release-Build angucken oder die asserts auskommentieren. Oder nicht Überlaufen lassen, oder bescheidsagen, wenn etwas überläuft, was nicht überlaufen soll.

Edit:
Ich update desen Abschnitt mit der Zeit.
1) Ich hab jetzt z.B. gerade gefixt, dass Divisionen manchmal mit absurd großen Typen geschehen, wenn das gar nicht notwendig ist.
2) Divisionen wie (a/b) / (c / d) werden nun zu (a*d) / (b*c) zusammengefasst.
Antworten