/* This program is distributed under the terms of the 'MIT license'. The text of this licence follows... Copyright (c) 2004-2005 J.D.Medhurst (a.k.a. Tixy) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** @file @brief 32-Bit fixed-point maths routines */ #ifndef __FIX_H__ #define __FIX_H__ /** @defgroup fix Maths - 32bit Fixed-Point Maths @brief Routines for performing 32bit fixed-point maths. This code is targeted at CPUs without hardware support for division or floating point. It has been optimised for ARM CPUs but should be suitable for other RISC architecures. @version 2006-05-20 - Changed code to use standard typedefs, e.g. replaced uint8 with uint8_t, and made use of size_t. @version 2006-06-04 - Added options to tune implementation of Fix::Mul(), Fix::MulNS() and Fix::Div(). See #FIX_USE_64BIT_MUL and #FIX_UNROLL_DIV_LOOP. @{ */ /** A type representing a 32bit fixed-point number. The binary point lies between bits 15 and 16. To convert between floating point and fixed point representations, numbers need scaling by 2 to-the-power-of 16 (65536) e.g. @code fix x; float f; // to convert f into x... x = (double)f*65536.0l; // to convert x into f... f = (double)x/65536.0l; @endcode Note, values are cast using (double) here to persuade the compiler to use double precision floating point arithmetic. This avoids loosing precision as single floats only have 24 significant bits, (less that the 32 bits in a fix number). To convert between int and fixed point types, shift values by 16. @code fix x; int i; // to convert i into x... x = i<<16; // to convert x into i (rounding towards minus infinity)... i = x>>16; // to convert x into i (rounding towards nearest integer)... i = ((x>>15)+1)>>1; @endcode Conversions described above may produce results which overflow the range which can be represented by fixed point numbers. To detect this, check the range of values before they are converted into fixed point... @code fix x; float f; // convert f into x... float temp = (double)f*65536.0l; if((double)-2147483648.0<=temp && temp<=(double)2147483647.0) x = temp; else printf("Number conversion overflow!"); @endcode or... @code fix x; int i; // convert i into x... if(-0x8000<=i && i<=0x7fff) x = i<<16; else printf("Number conversion overflow!"); @endcode */ typedef int32_t fix; /** A type representing a 32bit unsigned fixed-point number. The binary point lies between bits 15 and 16. For convertsion into/from fixed point format, see #fix. Note, valid input range fo unsigned values is 0..0xffff for integers, and 0..0xffffffff for the 'temp' value in the floating point conversion. */ typedef uint32_t ufix; /** A 32bit fixed-point value representing an angle. Values are scaled by a factor of 1/(2*PI), i.e. a value of 1.0 (0x10000) represents a full circle. To convert angles between floating point and fixed point representations, numbers need scaling as for #fix, but with the scaling factor reduced by 2*PI. E.g. @code #define PI 3.1415926535897932384626433832795l fixangle a; double f; // to convert f into a... a = (double)f*65536.0l/(2.0l*PI); // to convert a into f... f = (double)a/65536.0l*(2.0l*PI); @endcode This treats f as an angle in radians, (the usual units for angles in mathematics and computer functions). If you want to use values in degrees, replace 2.0l*PI with 360.0l. */ typedef fix fixangle; /** @brief Fixed point arithmetic functions. Operands are 32 bits in size with the binary point between bits 15 and 16. @see fix ufix fixangle @version 2005-02-26 - Added Random(uint32_t& seed) - Added Random(uint32_t& seed,ufix range) */ class Fix { public: /** Add two fixed-point numbers. Produces saturated result on overflow. When the addition of two numbers is know not to cause overflow, or when this doesn't matter, normal integer addition (+) can be used instead... @code fix a; fix b; fix sum = a+b; @endcode @param a Augend @param b Addend @return a+b.
If a+b>0x7FFF.FFFF then 0x7FFF.FFFF is returned.
If a+b<-0x8000.0000 then -0x8000.0000 is returned. */ IMPORT static fix Add(fix a,fix b); /** Subtract two fixed-point numbers. Produces saturated result on overflow. When the subtraction of two numbers is know not to cause overflow, or when this doesn't matter, normal integer subtraction (-) can be used instead... @code fix a; fix b; fix difference = a-b; @endcode @param a Minuend @param b Subtrahend @return a-b.
If a-b>0x7FFF.FFFF then 0x7FFF.FFFF is returned.
If a-b<-0x8000.0000 then -0x8000.0000 is returned. */ IMPORT static fix Sub(fix a,fix b); /** Multiply two fixed-point numbers. Produces saturated result on overflow. To multiply a fixed point number by an integer, normal integer multiplication (*) may be used... @code fix a; fix twoTimes = a*2; @endcode This does not detect overflow. @param a Multiplicand @param b Multiplier @return a*b.
If a*b>0x7FFF.FFFF then 0x7FFF.FFFF is returned.
If a*b<-0x8000.0000 then -0x8000.0000 is returned. @see MulNS() */ IMPORT static fix Mul(fix a,fix b); /** Multiply two fixed-point numbers. This is a Non-Saturating (and faster) version of Mul(). On overflow the result is undefined. To multiply a fixed point number by an integer, normal integer multiplication (*) may be used... @code fix a; fix twoTimes = a*2; @endcode @param a Multiplicand @param b Multiplier @return a*b.
If a*b>0x7FFF.FFFF or a*b<-0x8000.0000 then the returned result is undefined. */ IMPORT static fix MulNS(fix a,fix b); /** Divide two fixed-point numbers. Produces saturated result on overflow. Division by zero is treated as division by a very small number and produces a saturated result accordingly. To divide a fixed point number by an integer, normal integer division (/) may be used... @code fix a; fix half = a/2; @endcode This does not error conditions. @param a Dividend @param b Divisor @return a/b.
If a/b>0x7FFF.FFFF then 0x7FFF.FFFF is returned.
If a/b<-0x8000.0000 then -0x8000.0000 is returned.
If b==0 and a>=0 then 0x7FFF.FFFF is returned.
If b==0 and a<0 then -0x8000.0000 is returned.
*/ IMPORT static fix Div(fix a,fix b); /** Calculate the square root of a fixed-point number. @param a Unsigned fixed point number. @return a^0.5. */ IMPORT static fix Sqrt(ufix a); /** Calculate the logarithm to base 2 of a fixed-point number . Accuracy is +/-8.40e-6 (+/-0.55 lsb). @param a Unsigned fixed point number. @return log2(a).
If a==0 then -0x8000.0000 is returned */ IMPORT static fix Log2(ufix a); /** Raise 2 to-the-power of a fixed-point number, (2^a). Accuracy is +/-1.14e-5 (+/-0.75 lsb). @param a Fixed point number. @return 2^a.
If 2^a>0xFFFF.FFFF then 0xFFFF.FFFF is returned. */ IMPORT static ufix Exp2(fix a); /** Calculate the Sine of an angle. Accuracy is +/-8.55e-6 (+/-0.56 lsb). @param angle The angle. @return The Sine of \a angle. */ IMPORT static fix Sin(fixangle angle); /** Calculate the Cosine of an angle. Accuracy is +/-8.55e-6 (+/-0.56 lsb). @param angle The angle. @return The Cosine of \a angle. */ IMPORT static fix Cos(fixangle angle); /** Calculate the Tangent of an angle. Accuracy is +/-1.01e-5 (+/-0.66 lsb). @param angle The angle. @return The Tangent of \a angle.
If Tan(\a angle)>0x7FFF.FFFF then 0x7FFF.FFFF is returned.
If Tan(\a angle)<-0x8000.0000 then -0x8000.0000 is returned. */ IMPORT static fix Tan(fixangle angle); /** Calculate the Arc-Sine of a value. Accuracy is +/-8.55e-6 (+/-0.56 lsb). @param value The value. Should be in the range -1.0 to 1.0 (-0x10000 to 0x10000). @return The Arc-Sine of \a value.
If \a value<-1.0 then -0.25 (-0x4000) is returned.
If \a value>1.0 then 0.25 (0x4000) is returned. */ IMPORT static fixangle ASin(fix value); /** Calculate the Arc-Cosine of a value. Accuracy is +/-8.55e-6 (+/-0.56 lsb). @param value The value. Should be in the range -1.0 to 1.0 (-0x10000 to 0x10000). @return The Arc-Cosine of \a value.
If \a value<-1.0 then 0.5 (0x8000) is returned.
If \a value>1.0 then 0.0 (0x0000) is returned. */ IMPORT static fixangle ACos(fix value); /** Calculate the Arc-Tangent of a value. Accuracy is +/-9.00e-6 (+/-0.59 lsb). @param value The value. @return The Arc-Tangent of \a value. */ IMPORT static fixangle ATan(fix value); /** Generate a psuedo-random number. @param seed A reference to the seed value. This will be updated after each call to this function. @return A pseudo-random number @since 2005-02-26 */ IMPORT static fix Random(uint32_t& seed); /** Generate a psuedo-random number. @param seed A reference to the seed value. This will be updated after each call to this function. @param range The range for the generated numbers. @return A pseudo-random number less than the value of \a range @since 2005-02-26 */ IMPORT static ufix Random(uint32_t& seed,ufix range); }; /** @} */ // End of group #endif