#ifndef __MATH_FIXED_09022006_H__ #define __MATH_FIXED_09022006_H__ // Written by Michael Marcin (mike {at} mikemarcin.com) // Based on Evan Teran's fixed-point math template. // http://www.codef00.com/coding.php #include #include #include namespace boostish { namespace math { namespace detail { template< typename BaseType > struct raw_fixed { raw_fixed( BaseType r ) : data(r) {} BaseType data; }; // these allow us to determine reasonable types from a // desired size, they also let us infer the next largest type // from a type the division and multiplication ops template struct type_from_size { static const bool is_specialized = false; }; template<> struct type_from_size<64> { static const bool is_specialized = true; static const std::size_t size = 64; typedef boost::int64_t value_type; typedef type_from_size<32> prev_size; // no next size!, therefore we can't have a 32.32 fixed point value yet // or at the very least we will need to have a specialization of fixed to // do things diferently and not rely on a larger type }; template<> struct type_from_size<32> { static const bool is_specialized = true; static const std::size_t size = 32; typedef boost::int32_t value_type; typedef type_from_size<64> next_size; typedef type_from_size<16> prev_size; }; template<> struct type_from_size<16> { static const bool is_specialized = true; static const std::size_t size = 16; typedef boost::int16_t value_type; typedef type_from_size<32> next_size; typedef type_from_size<8> prev_size; }; template<> struct type_from_size<8> { static const bool is_specialized = true; static const std::size_t size = 8; typedef boost::int8_t value_type; typedef type_from_size<16> next_size; typedef type_from_size<8> prev_size; // would prefer a 4-bit type here, but 8 will do }; template< typename T > struct bit_size { static const std::size_t value = sizeof(T) * CHAR_BIT; }; } // type_from_size magic to allow as_fixed( 1<<16 ) instead of forcing as_fixed( int32_t( 1<<16) ) // also allows as_fixed( short(1<<8) ) instead of forcing as_fixed( int16_t(1<<8) ) template< typename T > inline detail::raw_fixed< typename detail::type_from_size< detail::bit_size::value >::value_type > as_fixed( T fixval ) { typedef typename detail::type_from_size< detail::bit_size::value >::value_type raw_type; return detail::raw_fixed( static_cast(fixval) ); } /// This class is meant to act as drop-in replacement for floating point types. template< std::size_t MagnitudeBits, std::size_t FractionalBits > class fixed : boost::operators< fixed > { BOOST_STATIC_ASSERT( detail::type_from_size::is_specialized ); public: typedef detail::type_from_size base_type_info; typedef typename base_type_info::value_type base_type; typedef typename base_type_info::next_size::value_type next_type; typedef typename base_type_info::prev_size::value_type prev_type; enum { fractional_bits = FractionalBits, magnitude_bits = MagnitudeBits, }; private: BOOST_STATIC_ASSERT( base_type_info::size - fractional_bits >= magnitude_bits ); static const base_type one = base_type(1)< raw ); fixed& operator = ( const fixed &rhs ); bool operator < ( const fixed &rhs ) const; bool operator == ( const fixed &rhs ) const; fixed& operator += ( const fixed &rhs ); fixed& operator -= ( const fixed &rhs ); fixed& operator *= ( const fixed &rhs ); fixed& operator /= ( const fixed &rhs ); fixed& operator ++ (); fixed& operator -- (); /// optimization for fixed *= integer fixed& operator *= ( int n ); /// optimization for fixed /= integer fixed& operator /= ( int n ); private: base_type data; template friend int to_integer( const fixed &f ); template friend float to_float( const fixed &f ); template friend double to_double( const fixed &f ); }; /// optimization for fixed * integer template fixed operator * ( fixed lhs, int rhs ); /// optimization for integer * fixed template fixed operator * ( int lhs, fixed rhs ); /// optimization for fixed / integer template fixed operator / ( fixed lhs, int rhs ); } // end namespace math } // end namespace boostish #include "fixed.inl" #endif //__MATH_FIXED_09022006_H__