// ----------------------------------------------------------------------------------------
//
//  common/util/fixedpoint.h
//    
//  Bob Cook Development, Robotics Library
//  http://www.bobcookdev.com/rl/
//    
//  This file provides a fixed-point numbers for 8.8 and 16.16 variants.
//
//  Copyright (C) 2008 Bob Cook
//
//      This program is free software; you can redistribute it and/or modify it
//      under the terms of the GNU General Public License as published by the
//      Free Software Foundation; either version 2 of the License, or (at your
//      option) any later version.
//    
//      This program is distributed in the hope that it will be useful, but 
//      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
//      or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
//      for more details.
//    
//      You should have received a copy of the GNU General Public License along
//      with this program; if not, write to the Free Software Foundation, Inc., 
//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// ----------------------------------------------------------------------------------------


#if !defined( BCDRL_COMMON_UTIL_FIXEDPOINT_H )
#define BCDRL_COMMON_UTIL_FIXEDPOINT_H


#include <stdint.h>


// ----------------------------------------------------------------------------------------
//  definitions from "project_defs.h"
//
//  enable conversion of strings to 16.16 and/or 8.8 fixed point numbers:
//
//      + PRJ_FIXED16DOT16_ENABLE_CONVERT_FROM_STRING
//      + PRJ_FIXED8DOT8_ENABLE_CONVERT_FROM_STRING
//
//	enable conversion from 16.16 and/or 8.8 fixed point numbers to doubles:
//
//		+ PRJ_FIXED16DOT16_ENABLE_CONVERT_TO_DOUBLE
//		+ PRJ_FIXED8DOT8_ENABLE_CONVERT_TO_DOUBLE
//
// ----------------------------------------------------------------------------------------

// ----------------------------------------------------------------------------------------
//  fixedpoint
//
//      A fixed-point number that can be templatized to specific bit layouts.
//

template< typename T_BASE_TYPE, unsigned T_DENOMINATOR_SIZE >
class fixedpoint
{
    public:

        // --------------------------------------------------------------------------------

		static const T_BASE_TYPE max_value
			= ( 1 << ( sizeof( T_BASE_TYPE ) * 8 - T_DENOMINATOR_SIZE - 1 ) );

		static const T_BASE_TYPE min_value
			= 1 - ( 1 << ( sizeof( T_BASE_TYPE ) * 8 - T_DENOMINATOR_SIZE - 1 ) );

		// --------------------------------------------------------------------------------
        //  Initialize a value to zero.
        //
        fixedpoint();

        // --------------------------------------------------------------------------------
        //  Copy constructor; default implementation is acceptable.
        //
        //fixedpoint( const fixedpoint& in );

        // --------------------------------------------------------------------------------
        //  Create a fixed-point value from an integer.
        //
        fixedpoint( T_BASE_TYPE integer );

        // --------------------------------------------------------------------------------
        //  Assignment operator; default implementation is acceptable.
        //
        //fixedpoint& operator=( const fixedpoint& in );

        // --------------------------------------------------------------------------------
        //  Various math operators.
        //
        fixedpoint operator+( const fixedpoint& value );
        fixedpoint operator-( const fixedpoint& value );
        fixedpoint operator*( const fixedpoint& value );
        fixedpoint operator/( const fixedpoint& value );

        fixedpoint& operator+=( const fixedpoint& value );
        fixedpoint& operator-=( const fixedpoint& value );
        fixedpoint& operator*=( const fixedpoint& value );
        fixedpoint& operator/=( const fixedpoint& value );

        // --------------------------------------------------------------------------------
        //  Convert to an integer.
        //
        T_BASE_TYPE asInteger() const;

        // --------------------------------------------------------------------------------
        //  Return the fractional portion i.e. value - asInteger().
        //
        T_BASE_TYPE asFractional() const;

        // --------------------------------------------------------------------------------
        //  Return the raw, packed version of the fixed-point number.
        //
        T_BASE_TYPE asRaw() const;

private:

        static fixedpoint fromRaw( T_BASE_TYPE raw );

        T_BASE_TYPE m_value;
};


// ----------------------------------------------------------------------------------------
//  The only supported specializations are 8.8 and 16.16. If other variants are desired
//  then specializations for multiplication and division is required.
//
//	The accuracy of 8.8 is 0.01 and of 16.16 is 0.0001.
//

typedef fixedpoint< int16_t,  8 > fixed8dot8;
typedef fixedpoint< int32_t, 16 > fixed16dot16;


// ----------------------------------------------------------------------------------------
//  fixed16dot16_from_string
//
//      Convert a floating point number, as a string, to a fixed16dot16 type.
//
//      Only compiled if PRJ_FIXED16DOT16_ENABLE_CONVERT_FROM_STRING is defined.
//

fixed16dot16 fixed16dot16_from_string( const char* str );


// ----------------------------------------------------------------------------------------
//  fixed8dot8_from_string
//
//      Convert a floating point number, as a string, to a fixed8dot8 type.
//
//      Only compiled if PRJ_FIXED8DOT8_ENABLE_CONVERT_FROM_STRING is defined.
//

fixed8dot8 fixed8dot8_from_string( const char* str );


// ----------------------------------------------------------------------------------------
//  fixed_to_double (fixed16dot16)
//
//      Convert a fixed point number back to a floating point number.
//
//      Only compiled if PRJ_FIXED16DOT16_ENABLE_CONVERT_TO_DOUBLE is defined.
//

double fixed_to_double( const fixed16dot16& fixed );


// ----------------------------------------------------------------------------------------
//  fixed_to_double (fixed8dot8)
//
//      Convert a fixed point number back to a floating point number.
//
//      Only compiled if PRJ_FIXED8DOT8_ENABLE_CONVERT_TO_DOUBLE is defined.
//

double fixed_to_double( const fixed8dot8& fixed );


// ----------------------------------------------------------------------------------------
//  Include the template functions.
//

#include "packages/common/util/fixedpoint.inl"


#endif // #if !defined( BCDRL_COMMON_UTIL_FIXEDPOINT_H )
// ----------------------------------------------------------------------------------------
//  end of fixedpoint.h
// ----------------------------------------------------------------------------------------

