007/include/LibFixedPoint.h

324 lines
11 KiB
C

/*========================================================================
* LibFixedPoint.h
*
* This library allows for complex fixed point math.
* it has greater flexibility than the gu functions (which are 32bit)
*
* example:
* FTOFIX32(100.5)
* will result in 6586368 (or 0x0064 8000) which is a s15.16 fixed format.
*
* #define fixed_fmt_z s16, 13, 2
* fixed(fixed_fmt_z) z;
* z.full = Float2Fixed(z, 7.3);
*
* will result in 402 (or 0x0192) which is s13.2 (as defined)
*
*========================================================================*/
/**************************************************************************
*
* $REVISION: 1.0 $
* $DATE: 2021/03/09 02:03:28 $
* $SOURCE: /include/LibFixedPoint.h,v $
*
**************************************************************************/
#ifndef _LIBFIXEDPOINT_H_
# define _LIBFIXEDPOINT_H_
#include <CPPLib.h>
#include <ultra64.h>
#pragma region Private Implementation Macros
#define _fixed(TYPE, INTEGER, FRACTION) \
union \
{ \
TYPE full; \
struct \
{ \
TYPE integer : INTEGER; \
TYPE fraction : FRACTION; \
} part; \
}
#define _Float2Fixed(SIZE, INTEGER, FRACTION, VALUE) ((VALUE) * (1 << FRACTION))
#define _Fixed2Float(SIZE, INTEGER, FRACTION, VALUE) \
((float)(VALUE) / (1 << FRACTION))
#define _GetFixedFraction(SIZE, INTEGER, FRACTION, VALUE) \
((unsigned SIZE)((1E##FRACTION) * \
(VALUE.part.fraction & ((1 << FRACTION) - 1))) / \
(1 << FRACTION))
#define _FixedAddition(SIZE_A, \
INTEGER_A, \
FRACTION_A, \
VALUE_A, \
SIZE_B, \
INTEGER_B, \
FRACTION_B, \
VALUE_B) \
(SIZE_A) VALUE_A + (VALUE_B << (FRACTION_A - FRACTION_B))
#define _FixedSubtraction(SIZE_A, \
INTEGER_A, \
FRACTION_A, \
VALUE_A, \
SIZE_B, \
INTEGER_B, \
FRACTION_B, \
VALUE_B) \
(SIZE_A) VALUE_A - (VALUE_B << (FRACTION_A - FRACTION_B))
#define _FixedMultiplication(SIZE_A, \
INTEGER_A, \
FRACTION_A, \
VALUE_A, \
SIZE_B, \
INTEGER_B, \
FRACTION_B, \
VALUE_B) \
(VALUE_A * VALUE_B) >> (FRACTION_A - FRACTION_B)
#define _FixedDivision(SIZE_A, \
INTEGER_A, \
FRACTION_A, \
VALUE_A, \
SIZE_B, \
INTEGER_B, \
FRACTION_B, \
VALUE_B) \
(VALUE_A << (FRACTION_A - FRACTION_B) / VALUE_B)
#pragma endregion
#pragma region Public Macros
/**
* Define a Fixed Point type.
* Please Define the format Directly Before this.
* #define fixed_fmt_VarName Size,Integer,Fraction
* @param FORMAT: format name eg, fixed_fmt_VarName
*/
#define fixed(FORMAT) EXPAND(_fixed(FORMAT))
/**
* Convert a float to a Fixed Point type (integer).
* @param VAR: Variable to assign VALUE to.
* @param VALUE: Float Value to convert.
*/
#define Float2Fixed(VAR, VALUE) \
EXPAND(DEFER(_Float2Fixed)(EXPAND(fixed_fmt_##VAR), VALUE))
/**
* Convert a Fixed Point type (integer) to a float.
* @param VAR: Variable to convert.
*/
#define Fixed2Float(VAR) \
EXPAND(DEFER(_Fixed2Float)(EXPAND(fixed_fmt_##VAR), VAR.full))
/**
* @param VAR: Fixed Type to Read.
* @return Scaled Integer representing the Fractional Componant. eg, 75 for 0.75
*/
#define GetFixedFraction(VAR) \
EXPAND(DEFER(_GetFixedFraction)(EXPAND(fixed_fmt_##VAR), VAR))
/**
* Perform Addition on 2 Fixed Types.
* If A and B are different types, the larger should come first.
* @param A: Fixed Type to Read.
* @param B: Fixed Type to Read.
* @return Integer of Fixed Type "A".
*/
#define FixedAddition(A, B) \
EXPAND(DEFER(_FixedAddition)(EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##B), \
B.full))
/**
* Perform Addition on A Fixed Type and Integer.
* @param A: Fixed Type to Read.
* @param B: Integer.
* @return Integer of Fixed Type "A".
*/
#define FixedAddition_i(A, B) \
EXPAND(DEFER(_FixedAddition)(EXPAND(fixed_fmt_##A), \
A.full, \
0, 0, 0, \
B))
/**
* Perform Addition on A Fixed Type and Float.
* @param A: Fixed Type to Read.
* @param B: Float.
* @return Integer of Fixed Type "A".
*/
#define FixedAddition_f(A, B) \
EXPAND(DEFER(_FixedAddition)( \
EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##A), \
EXPAND(DEFER(_Float2Fixed)(EXPAND(fixed_fmt_##A), B))))
/**
* Perform Subtraction on 2 Fixed Types.
* If A and B are different types, the larger should come first.
* @param A: Fixed Type to Read.
* @param B: Fixed Type to Read.
* @return Integer of Fixed Type "A".
*/
#define FixedSubtraction(A, B) \
EXPAND(DEFER(_FixedSubtraction)(EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##B), \
B.full))
/**
* Perform Subtraction on A Fixed Type and Integer.
* @param A: Fixed Type to Read.
* @param B: Integer.
* @return Integer of Fixed Type "A".
*/
#define FixedSubtraction_i(A, B) \
EXPAND(DEFER(_FixedSubtraction)(EXPAND(fixed_fmt_##A), A.full, 0, 0, 0, B))
/**
* Perform Subtraction on A Fixed Type and Float.
* @param A: Fixed Type to Read.
* @param B: Float.
* @return Integer of Fixed Type "A".
*/
#define FixedSubtraction_f(A, B) \
EXPAND(DEFER(_FixedSubtraction)( \
EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##A), \
EXPAND(DEFER(_Float2Fixed)(EXPAND(fixed_fmt_##A), B))))
/**
* Perform Multiplication on 2 Fixed Types.
* If A and B are different types, the larger Fractional should come first.
* @param A: Fixed Type to Read.
* @param B: Fixed Type to Read.
* @return Integer with "A" bits fraction.
*/
#define FixedMultiplication(A, B) \
EXPAND(DEFER(_FixedMultiplication)(EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##B), \
B.full))
/**
* Perform Multiplication on A Fixed Type and Integer.
* @param A: Fixed Type to Read.
* @param B: Integer.
* @return Integer of Fixed Type "A".
*/
#define FixedMultiplication_i(A, B) \
EXPAND(DEFER( \
_FixedMultiplication)(EXPAND(fixed_fmt_##A), A.full, 0, 0, 0, B))
/**
* Perform Multiplication on A Fixed Type and Float.
* @param A: Fixed Type to Read.
* @param B: Float.
* @return Integer of Fixed Type "A".
*/
#define FixedMultiplication_f(A, B) \
EXPAND(DEFER(_FixedMultiplication)( \
EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##A), \
EXPAND(DEFER(_Float2Fixed)(EXPAND(fixed_fmt_##A), B))))
/**
* Perform Division on 2 Fixed Types.
* If A and B are different types, the larger Fractional should come first.
* @param A: Fixed Type to Read.
* @param B: Fixed Type to Read.
* @return Integer with "A" bits fraction.
*/
#define FixedDivision(A, B) \
EXPAND(DEFER(_FixedDivision)(EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##B), \
B.full))
/**
* Perform Division on A Fixed Type and Integer.
* @param A: Fixed Type to Read.
* @param B: Integer.
* @return Integer of Fixed Type "A".
*/
#define FixedDivision_i(A, B) \
EXPAND(DEFER(_FixedDivision)(EXPAND(fixed_fmt_##A), A.full, 0, 0, 0, B))
/**
* Perform Division on A Fixed Type and Float.
* @param A: Fixed Type to Read.
* @param B: Float.
* @return Integer of Fixed Type "A".
*/
#define FixedDivision_f(A, B) \
EXPAND(DEFER(_FixedDivision)( \
EXPAND(fixed_fmt_##A), \
A.full, \
EXPAND(fixed_fmt_##A), \
EXPAND(DEFER(_Float2Fixed)(EXPAND(fixed_fmt_##A), B))))
#if 0
/**
* Example Showing all Fixed Types and a comparison to Float.
* Result: Use Fixed for Storage and float for runtime.
*/
void Example()
{
#define fixed_fmt_y unsigned char, 3, 1
fixed(fixed_fmt_y) y; // 1bytes
#define fixed_fmt_z short, 13, 2
fixed(fixed_fmt_z) z; // 2bytes
#define fixed_fmt_Result short, 14, 2
fixed(fixed_fmt_Result) Result; // 2bytes
float Comparitor; // 4bytes
Comparitor = 6.5; // 1 Instructions
z.full = Float2Fixed(z, 7.3);
printf("\n Zfull = %d", z.full); // 29 1 Instructions
printf("\n Zint = %d", z.part.integer); // 7 3 Instructions
printf("\n Zfrac = %d", z.part.fraction); // 1 5 Instructions
printf("\n Zfixedfulldec = %d.%u",
z.part.integer,
GetFixedFraction(z)); // 7, 25 41 Instructions
printf("\n ZFixed2Float = %g", Fixed2Float(z)); // 7.25 7 Instructions
y.full = 4;
printf("\n y = %g", Fixed2Float(y)); // 2
Result.full = FixedMultiplication(z, y); // 9 Instructions
printf("\n Result = %g", Fixed2Float(Result)); // 14.5
Result.full = FixedDivision(z, y); // 9 Instructions
printf("\n Result = %g", Fixed2Float(Result)); // 3.5
Result.full = FixedSubtraction(z, y); // 6 Instructions
printf("\n Result = %g", Fixed2Float(Result)); // 5.25
Result.full = FixedAddition(z, y); // 6 Instructions
printf("\n Result = %g", Fixed2Float(Result)); // 9.25
printf("\n Comparison = %g", Comparitor); // 6.5 3 Instructions
Comparitor *= 2.6; // 4 Instructions
printf("\n Comparison = %g", Comparitor); // 16.9
}
#endif
#pragma endregion
#endif