514 lines
19 KiB
HTML
514 lines
19 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
|
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
|
<title>EAFixedPoint</title>
|
|
<meta name="author" content="Paul Pedriana">
|
|
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
|
</head>
|
|
<body bgcolor="#FFFFFF">
|
|
<h1>EAFixedPoint</h1>
|
|
<h2> <span style="font-weight: bold;">Introduction</span> </h2>
|
|
<p>The EAFixedPoint module implements fixed point math via classic C macros and
|
|
functions and via a more advanced implementation using C++ classes. The C++
|
|
classes constitute a fairly complete implementation of a fixed point C++ numerical
|
|
data type that acts much like the built-in float and double data types. </p>
|
|
<p>The following code freely mixes the SFixed16 (signed 16:16 fixed point) data
|
|
type with other numerical data types:</p>
|
|
<pre><span style="font-family: monospace;"><span class="code-example">SFixed16_16 a(1), b(2), c(3);<br>float f(4.5f);<br>double d(3.2);<br>int i(6);
|
|
<br>a = b * f;<br>a = (c / d) + b + f;<br>a = c / d * (b % i) + f / c;<br>a = i * -c / (b++);<br>a = sin(a) + pow(b, d) * sqrt(a);<br>a = log(a) / log(f);</span></span></pre>
|
|
<p></p>
|
|
<p>Fixed point math has a number of uses:</p>
|
|
<ul>
|
|
<li>Improved precision over floating point math.</li>
|
|
<li>Improved speed over floating point math, particularly with respect to division.</li>
|
|
<li>Consistent behaviour across CPUs, especially during network play when two
|
|
different machines must behave identically but FPU behaviour may differ.</li>
|
|
</ul>
|
|
<p>Information about fixed point can be found on the Internet by simply searching
|
|
for "fixed point" with your favorite search site.</p>
|
|
<h2>Fixed point vs. floating point </h2>
|
|
<p>Fixed point</p>
|
|
<blockquote>
|
|
<p>+ Can be very fast. Fixed point
|
|
math executes at the same speed as integer math. Fixed to int conversions
|
|
are much faster float to int.<br>
|
|
+ Executes concurrently with floating point math, due its use of integer math.<br>
|
|
– Limited range. Fixed point16:16 numbers are between -32767 and +32767.
|
|
The fractional part is accurate to 1 / 65536. <br>
|
|
– Harder to code in high-level languages.</p>
|
|
</blockquote>
|
|
<p>Floating point</p>
|
|
<blockquote>
|
|
<p>+ Large range. The range for floating point numbers is typically in excess
|
|
of 1e-100 to 1e+100 and have an accuracy of about 13 decimal places. <br>
|
|
+ Executes concurrently with integer math.<br>
|
|
– Can be slower. Generally
|
|
fast for addition and multiplication but may be slower for division and float
|
|
to int conversions. </p>
|
|
</blockquote>
|
|
<h2>Fixed point precision </h2>
|
|
<p>The C++ fixed point classes provide varying precision via the use of template
|
|
parameter constants. EAFixedPoint provides the following predefined C++ fixed
|
|
point types</p>
|
|
<table width="100%" border="1">
|
|
<tr>
|
|
<td><b>Type</b></td>
|
|
<td><b>Signed</b></td>
|
|
<td><b>Integral type</b></td>
|
|
<td><b>Precision</b></td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed24_8</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>24 bits of integer, 8 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed24_8</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>24 bits of integer, 8 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed22_10</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>22 bits of integer, 10 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed22_10</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>22 bits of integer, 10 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed20_12</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>20 bits of integer, 12 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed20_12</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>20 bits of integer, 12 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed18_14</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>18 bits of integer, 14 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed18_14</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>18 bits of integer, 14 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed16_16</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>16 bits of integer, 16 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed16_16</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>16 bits of integer, 16 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed14_18</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>14 bits of integer, 18 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed14_18</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>14 bits of integer, 18 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed12_20</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>12 bits of integer, 20 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed12_20</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>12 bits of integer, 20 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed10_22</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>10 bits of integer, 22 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed10_22</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>10 bits of integer, 22 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed8_24</font></td>
|
|
<td>signed</td>
|
|
<td>32</td>
|
|
<td>8 bits of integer, 24 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed8_24</font></td>
|
|
<td>unsigned</td>
|
|
<td>32</td>
|
|
<td>8 bits of integer, 24 bits of fraction</td>
|
|
</tr>
|
|
<tr>
|
|
<td> </td>
|
|
<td> </td>
|
|
<td> </td>
|
|
<td> </td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed48_16</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>48 bits of integer, 16 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed48_16</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>48 bits of integer, 16 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed44_20</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>44 bits of integer, 20 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed44_20</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>44 bits of integer, 20 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed40_24</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>40 bits of integer, 24 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed40_24</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>40 bits of integer, 24 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed36_28</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>36 bits of integer, 28 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed36_28</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>36 bits of integer, 28 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed32_32</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>32 bits of integer, 32 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed32_32</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>32 bits of integer, 32 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed28_36</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>28 bits of integer, 36 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed28_36</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>28 bits of integer, 36 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed24_40</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>24 bits of integer, 40 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed24_40</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>24 bits of integer, 40 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed20_44</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>20 bits of integer, 44 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed20_44</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>20 bits of integer, 44 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">SFixed16_48</font></td>
|
|
<td>signed</td>
|
|
<td>64</td>
|
|
<td>16 bits of integer, 48 bits of fraction.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New, Courier, mono" size="-1">UFixed16_48</font></td>
|
|
<td>unsigned</td>
|
|
<td>64</td>
|
|
<td>16 bits of integer, 48 bits of fraction.</td>
|
|
</tr>
|
|
</table>
|
|
<h2>Example usage </h2>
|
|
<p>To a large degree, you can use fixed point types the same way you would use
|
|
floating point types. </p>
|
|
<p>Mixed integer math expressions (same as shown earlier above):</p>
|
|
<pre class="code-example">SFixed16_16 a(1), b(2), c(3);<br>float f(4.5f);<br>double d(3.2);<br>int i(6);
|
|
<br>a = b * f;<br>a = (c / d) + b + f;<br>a = c / d * (b % i) + f / c;<br>a = i * -c / (b++);<br>a = sin(a) + pow(b, d) * sqrt(a);<br>a = log(a) / log(f);</pre>
|
|
<p>printf:</p>
|
|
<pre class="code-example">SFixed24_8 f = 23.5f;<br><br>printf("%f", f.AsFloat());</pre>
|
|
<p>Logical expresions:</p>
|
|
<pre class="code-example">SFixed16_16 a = 20.4;
|
|
SFixed16_16 b = 130.6;
|
|
SFixed16_16 c = 223.3;
|
|
|
|
if((a < b) || (b >= c) || (a < 23.5))
|
|
a *= 25;</pre>
|
|
<h2>Limitations </h2>
|
|
<p>The primary differences between our fixed point type and a hypothetical built-in
|
|
version are:</p>
|
|
<ul>
|
|
<li>EAFixedPoint doesn't implement cast operators. Instead, provides explicit
|
|
converters such as AsInt, AsFloat, etc. This is by design, as such casting
|
|
operators result in ambiguous conversions and would need built-in compiler
|
|
knowledge to resolve the situation.</li>
|
|
<li>Standard library functions such as sprintf have no support for such fixed
|
|
point types. However, most of the time it is sufficient to convert to floating
|
|
point and use the built-in floating point formatting functions.</li>
|
|
<li>There is no explicit support for mixing expressions between two different
|
|
fixed point types, such as SFixed16_16 with SFixed24_8. You can use these
|
|
together via conversion between built-in types. </li>
|
|
</ul>
|
|
<h2>Interface </h2>
|
|
<p>C interface:</p>
|
|
<pre class="code-example">typedef int32_t EAFixed16;
|
|
|
|
#define EAMAX_FIXED16 0x7fffffff
|
|
#define EAMIN_FIXED16 0x80000000
|
|
|
|
#define EAFixed16ToInt(a) ((int32_t)(a) >> 16)
|
|
#define EAIntToFixed16(a) ((EAFixed16)((a) << 16))
|
|
#define EAFixed16ToDouble(a) (((double)a) / 65536.0)
|
|
#define EADoubleToFixed16(a) ((EAFixed16)((a) * 65536.0))
|
|
#define EAFixed16ToFloat(a) (((float)a) / 65536.f)
|
|
#define EAFloatToFixed16(a) ((EAFixed16)((a) * 65536.f))
|
|
#define EAFixed16Negate(a) (-a)
|
|
|
|
EAFixed16 EAFixed16Mul (EAFixed16 a, EAFixed16 b);
|
|
EAFixed16 EAFixed16Div (EAFixed16 a, EAFixed16 b);
|
|
EAFixed16 EAFixed16DivSafe (EAFixed16 a, EAFixed16 b);
|
|
EAFixed16 EAFixed16MulDiv (EAFixed16 a, EAFixed16 b, EAFixed16 c);
|
|
EAFixed16 EAFixed16MulDivSafe (EAFixed16 a, EAFixed16 b, EAFixed16 c);
|
|
EAFixed16 EAFixed16Mod (EAFixed16 a, EAFixed16 b);
|
|
EAFixed16 EAFixed16ModSafe (EAFixed16 a, EAFixed16 b);
|
|
EAFixed16 EAFixed16Abs (EAFixed16 a);
|
|
</pre>
|
|
<p>C++ interface, by example of SFixed16_16. Note that nearly all the functions
|
|
below are implemented as simple inlines:</p>
|
|
<pre class="code-example">struct SFixed16_16
|
|
{
|
|
SFixed16_16();
|
|
SFixed16_16(const SFixed16_16& value);
|
|
SFixed16_16(const int& value);
|
|
SFixed16_16(const unsigned int& value);
|
|
SFixed16_16(const long& value);
|
|
SFixed16_16(const unsigned long& value);
|
|
SFixed16_16(const float& value);
|
|
SFixed16_16(const double& value);
|
|
|
|
void FromFixed(const int& value);
|
|
int32_t AsFixed();
|
|
|
|
int AsInt() const;
|
|
unsigned int AsUnsignedInt() const;
|
|
long AsLong() const;
|
|
unsigned long AsUnsignedLong()const;
|
|
float AsFloat() const;
|
|
double AsDouble() const;
|
|
|
|
SFixed16_16& operator=(const SFixed16_16& value);
|
|
SFixed16_16& operator=(const int& value);
|
|
SFixed16_16& operator=(const unsigned int& value);
|
|
SFixed16_16& operator=(const long& value);
|
|
SFixed16_16& operator=(const unsigned long& value);
|
|
SFixed16_16& operator=(const float& value);
|
|
SFixed16_16& operator=(const double& value);
|
|
|
|
bool operator< (const SFixed16_16& value) const;
|
|
bool operator> (const SFixed16_16& value) const;
|
|
bool operator>=(const SFixed16_16& value) const;
|
|
bool operator<=(const SFixed16_16& value) const;
|
|
bool operator==(const SFixed16_16& value) const;
|
|
bool operator!=(const SFixed16_16& value) const;
|
|
|
|
bool operator< (const int& value) const;
|
|
bool operator> (const int& value) const;
|
|
bool operator>=(const int& value) const;
|
|
bool operator<=(const int& value) const;
|
|
bool operator==(const int& value) const;
|
|
bool operator!=(const int& value) const;
|
|
|
|
bool operator< (const unsigned int& value) const;
|
|
bool operator> (const unsigned int& value) const;
|
|
bool operator>=(const unsigned int& value) const;
|
|
bool operator<=(const unsigned int& value) const;
|
|
bool operator==(const unsigned int& value) const;
|
|
bool operator!=(const unsigned int& value) const;
|
|
|
|
bool operator< (const long& value) const;
|
|
bool operator> (const long& value) const;
|
|
bool operator>=(const long& value) const;
|
|
bool operator<=(const long& value) const;
|
|
bool operator==(const long& value) const;
|
|
bool operator!=(const long& value) const;
|
|
|
|
bool operator< (const unsigned long& value) const;
|
|
bool operator> (const unsigned long& value) const;
|
|
bool operator>=(const unsigned long& value) const;
|
|
bool operator<=(const unsigned long& value) const;
|
|
bool operator==(const unsigned long& value) const;
|
|
bool operator!=(const unsigned long& value) const;
|
|
|
|
bool operator< (const float& value) const;
|
|
bool operator> (const float& value) const;
|
|
bool operator>=(const float& value) const;
|
|
bool operator<=(const float& value) const;
|
|
bool operator==(const float& value) const;
|
|
bool operator!=(const float& value) const;
|
|
|
|
bool operator< (const double& value) const;
|
|
bool operator> (const double& value) const;
|
|
bool operator>=(const double& value) const;
|
|
bool operator<=(const double& value) const;
|
|
bool operator==(const double& value) const;
|
|
bool operator!=(const double& value) const;
|
|
bool operator! () const;
|
|
|
|
SFixed16_16 operator~() const;
|
|
SFixed16_16 operator-() const;
|
|
SFixed16_16 operator+() const;
|
|
|
|
SFixed16_16& operator+=(const SFixed16_16& value);
|
|
SFixed16_16& operator+=(const int& value);
|
|
SFixed16_16& operator+=(const unsigned int& value);
|
|
SFixed16_16& operator+=(const long & value);
|
|
SFixed16_16& operator+=(const unsigned long& value);
|
|
SFixed16_16& operator+=(const float& value);
|
|
SFixed16_16& operator+=(const double& value);
|
|
|
|
SFixed16_16& operator-=(const SFixed16_16& value);
|
|
SFixed16_16& operator-=(const int& value);
|
|
SFixed16_16& operator-=(const unsigned int& value);
|
|
SFixed16_16& operator-=(const long& value);
|
|
SFixed16_16& operator-=(const unsigned long& value);
|
|
SFixed16_16& operator-=(const float& value);
|
|
SFixed16_16& operator-=(const double& value);
|
|
|
|
SFixed16_16& operator*=(const SFixed16_16& value);
|
|
SFixed16_16& operator*=(const int& value)
|
|
SFixed16_16& operator*=(const unsigned int& value)
|
|
SFixed16_16& operator*=(const long& value)
|
|
SFixed16_16& operator*=(const unsigned long& value);
|
|
SFixed16_16& operator*=(const float& value);
|
|
SFixed16_16& operator*=(const double& value);
|
|
|
|
SFixed16_16& operator/=(const SFixed16_16& value);
|
|
SFixed16_16& operator/=(const int& value);
|
|
SFixed16_16& operator/=(const unsigned int& value);
|
|
SFixed16_16& operator/=(const long& value);
|
|
SFixed16_16& operator/=(const unsigned long& value);
|
|
SFixed16_16& operator/=(const float& value);
|
|
SFixed16_16& operator/=(const double& value);
|
|
|
|
SFixed16_16& operator%=(const SFixed16_16& value);
|
|
SFixed16_16& operator%=(const int& value);
|
|
SFixed16_16& operator%=(const unsigned int& value);
|
|
SFixed16_16& operator%=(const long& value);
|
|
SFixed16_16& operator%=(const unsigned long& value);
|
|
SFixed16_16& operator%=(const float& value);
|
|
SFixed16_16& operator%=(const double& value);
|
|
|
|
SFixed16_16& operator|=(const SFixed16_16& value);
|
|
SFixed16_16& operator|=(const int& value);
|
|
|
|
SFixed16_16& operator&=(const SFixed16_16& value);
|
|
SFixed16_16& operator&=(const int& value);
|
|
|
|
SFixed16_16& operator^=(const SFixed16_16& value);
|
|
SFixed16_16& operator^=(const int& value);
|
|
|
|
SFixed16_16 operator<<(int numBits) const;
|
|
SFixed16_16 operator>>(int numBits) const;
|
|
|
|
SFixed16_16& operator<<=(int numBits);
|
|
SFixed16_16& operator>>=(int numBits);
|
|
|
|
SFixed16_16& operator++();
|
|
SFixed16_16& operator--();
|
|
SFixed16_16 operator++(int);
|
|
SFixed16_16 operator--(int);
|
|
|
|
SFixed16_16 Abs();
|
|
SFixed16_16 DivSafe(const SFixed16_16& denominator);
|
|
SFixed16_16& DivSafeAssign(const SFixed16_16& denominator);
|
|
}<font color="#000099">;</font>
|
|
</pre>
|
|
<hr>
|
|
<p><br>
|
|
<br>
|
|
<br>
|
|
<span style="font-family: monospace;"> </span><br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
</p>
|
|
</body></html> |