#ifndef __MATH16_H__
#define __MATH16_H__

#ifdef __cplusplus
extern "C" {
#endif 

// Type for fixed point 16.16 numbers.  I used LONG as the base type because it is the only
// type I could find guarantied to stay a 32 bit signed number, even when we convert to
// 64 bit machines.
typedef LONG	FIXED16_16;

// Constants for dealing with shifting the bits around in the 16.16 format.
#define	SHFTBITS    16

#define LOWMASK	    ((1 << SHFTBITS)-1)
#define HGHMASK	    (~LOWMASK)
#define LOWBITS(x)  ((x) & LOWMASK)
#define HGHBITS(x)  ((x) & HGHMASK)
#define	LSHFT(x)    ((x) << SHFTBITS)
#define RSHFT(x)    ((x) >> SHFTBITS)

// Useful constants in 16.16 form
#define	PI				(3373259427 >> (30-SHFTBITS))
#define TWOPI			(PI << 1)
#define PIOVER2			(PI >> 1)
#define	ONE_POINT_ZERO	0x00010000		// (1 << SHFTBITS), but prefast complains when cast to double

// How many bits needed to store a number.
#define Need(dw) (dw & 0xFF000000 ? 32 : (dw & 0x00FF0000 ? 24 : (dw & 0x0000FF00 ? 16 : 8)))

// Convert number to 16.16 form.
#define	IntToFix16(val)		(((FIXED16_16)(val)) << SHFTBITS)
#define	FloatToFix16(val)	((FIXED16_16)((val) * (double)ONE_POINT_ZERO))

// Convert 16.16 form to a number.
#define	Fix16ToInt(val)		RSHFT(val)
#define	Fix16ToFloat(val)	((val) / (double)ONE_POINT_ZERO)

// Convert other fixed point forms to a double.
// If the value of N (number of fractional bits) is a constant, this is much faster then shifting 
// and using Fix16ToFloat.  If N is a variable, the 64 bit shift is very expensive.
#define	FixNToFloat(val, n)	((val) / (double)((_int64)1 << n))

// Compute a sigmoid on a 16.16 number.
FIXED16_16	Sigmoid16(FIXED16_16 iX);

// Add two 16.16 numbers.  We just do the macro for clearity and documentation, because
// add just works.
#define	Add16(iX, iY)	(iX + iY)

// The same for subtraction.
#define	Sub16(iX, iY)	(iX - iY)

// Dived two 16.16 numbers.
FIXED16_16	Div16(FIXED16_16 iX, FIXED16_16 iY);

// Multiply two 16.16 numbers.  This uses Greg's multiplication algorithm:
typedef struct {
	unsigned short frac;
	short whole;
} FIX1616, *PFIX1616;

#define Mul16(a,b,c) {	\
	FIXED16_16 i1, i2;									\
	FIX1616 fix1, fix2;									\
	i1=(a);												\
	i2=(b);												\
	fix1 = *(PFIX1616)&i1;								\
	fix2 = *(PFIX1616)&i2;								\
	c = (DWORD)(fix1.frac*fix2.frac) >> 16;				\
	c += fix1.frac*fix2.whole + fix1.whole*fix2.frac;	\
	c += (fix1.whole*fix2.whole) << 16;					\
}

#ifdef __cplusplus
}
#endif

#endif // __MATH16_H__