292 lines
5.9 KiB
C++
292 lines
5.9 KiB
C++
/*
|
|
* \file fastmath.cxx
|
|
* fast mathematics routines.
|
|
*
|
|
* Refferences:
|
|
*
|
|
* A Fast, Compact Approximation of the Exponential Function
|
|
* Nicol N. Schraudolph
|
|
* IDSIA, Lugano, Switzerland
|
|
* http://www.inf.ethz.ch/~schraudo/pubs/exp.pdf
|
|
*
|
|
* Base-2 exp, Laurent de Soras
|
|
* http://www.musicdsp.org/archive.php?classid=5#106
|
|
*
|
|
* Fast log() Function, by Laurent de Soras:
|
|
* http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-Fastlogfunction&forum=totd&id=-1
|
|
*
|
|
* Sin, Cos, Tan approximation
|
|
* http://www.musicdsp.org/showArchiveComment.php?ArchiveID=115
|
|
*
|
|
* fast floating point power computation:
|
|
* http://playstation2-linux.com/download/adam/power.c
|
|
*/
|
|
|
|
/*
|
|
* $Id$
|
|
*/
|
|
|
|
|
|
|
|
#include "fastmath.hxx"
|
|
#define SGD_PI_2 1.57079632679489661923
|
|
|
|
/**
|
|
* This function is on avarage 9 times faster than the system exp() function
|
|
* and has an error of about 1.5%
|
|
*/
|
|
static union {
|
|
double d;
|
|
struct {
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
int i, j;
|
|
#else
|
|
int j, i;
|
|
#endif
|
|
} n;
|
|
} _eco;
|
|
|
|
double fast_exp(double val) {
|
|
const double a = 1048576/M_LN2;
|
|
const double b_c = 1072632447; /* 1072693248 - 60801 */
|
|
|
|
_eco.n.i = (int)(a*val + b_c);
|
|
|
|
return _eco.d;
|
|
}
|
|
|
|
/*
|
|
* Linear approx. between 2 integer values of val. Uses 32-bit integers.
|
|
* Not very efficient but faster than exp()
|
|
*/
|
|
double fast_exp2( const double val )
|
|
{
|
|
int e;
|
|
double ret;
|
|
|
|
if (val >= 0) {
|
|
e = int (val);
|
|
ret = val - (e - 1);
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
((*((int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
|
|
#else
|
|
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += (e + 1023) << 20;
|
|
#endif
|
|
} else {
|
|
e = int (val + 1023);
|
|
ret = val - (e - 1024);
|
|
|
|
#if BYTE_ORDER == BIG_ENDIAN
|
|
((*((int *) &ret)) &= ~(2047 << 20)) += e << 20;
|
|
#else
|
|
((*(1 + (int *) &ret)) &= ~(2047 << 20)) += e << 20;
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
float _fast_log2(const float val)
|
|
{
|
|
float result, tmp;
|
|
float mp = 0.346607f;
|
|
|
|
result = *(int*)&val;
|
|
result *= 1.0/(1<<23);
|
|
result = result - 127;
|
|
|
|
tmp = result - floor(result);
|
|
tmp = (tmp - tmp*tmp) * mp;
|
|
return tmp + result;
|
|
}
|
|
|
|
float _fast_pow2(const float val)
|
|
{
|
|
float result;
|
|
|
|
float mp = 0.33971f;
|
|
float tmp = val - floor(val);
|
|
tmp = (tmp - tmp*tmp) * mp;
|
|
|
|
result = val + 127 - tmp;
|
|
result *= (1<<23);
|
|
*(int*)&result = (int)result;
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* While we're on the subject, someone might have use for these as well?
|
|
* Float Shift Left and Float Shift Right. Do what you want with this.
|
|
*/
|
|
void fast_BSL(float &x, register unsigned long shiftAmount) {
|
|
|
|
*(unsigned long*)&x+=shiftAmount<<23;
|
|
|
|
}
|
|
|
|
void fast_BSR(float &x, register unsigned long shiftAmount) {
|
|
|
|
*(unsigned long*)&x-=shiftAmount<<23;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* fastpow(f,n) gives a rather *rough* estimate of a float number f to the
|
|
* power of an integer number n (y=f^n). It is fast but result can be quite a
|
|
* bit off, since we directly mess with the floating point exponent.
|
|
*
|
|
* Use it only for getting rough estimates of the values and where precision
|
|
* is not that important.
|
|
*/
|
|
float fast_pow(const float f, const int n)
|
|
{
|
|
long *lp,l;
|
|
lp=(long*)(&f);
|
|
l=*lp;l-=0x3F800000l;l<<=(n-1);l+=0x3F800000l;
|
|
*lp=l;
|
|
return f;
|
|
}
|
|
|
|
float fast_root(const float f, const int n)
|
|
{
|
|
long *lp,l;
|
|
lp=(long*)(&f);
|
|
l=*lp;l-=0x3F800000l;l>>=(n-1);l+=0x3F800000l;
|
|
*lp=l;
|
|
return f;
|
|
}
|
|
|
|
|
|
/*
|
|
* Code for approximation of cos, sin, tan and inv sin, etc.
|
|
* Surprisingly accurate and very usable.
|
|
*
|
|
* Domain:
|
|
* Sin/Cos [0, pi/2]
|
|
* Tan [0,pi/4]
|
|
* InvSin/Cos [0, 1]
|
|
* InvTan [-1, 1]
|
|
*/
|
|
|
|
float fast_sin(const float val)
|
|
{
|
|
float fASqr = val*val;
|
|
float fResult = -2.39e-08f;
|
|
fResult *= fASqr;
|
|
fResult += 2.7526e-06f;
|
|
fResult *= fASqr;
|
|
fResult -= 1.98409e-04f;
|
|
fResult *= fASqr;
|
|
fResult += 8.3333315e-03f;
|
|
fResult *= fASqr;
|
|
fResult -= 1.666666664e-01f;
|
|
fResult *= fASqr;
|
|
fResult += 1.0f;
|
|
fResult *= val;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
float fast_cos(const float val)
|
|
{
|
|
float fASqr = val*val;
|
|
float fResult = -2.605e-07f;
|
|
fResult *= fASqr;
|
|
fResult += 2.47609e-05f;
|
|
fResult *= fASqr;
|
|
fResult -= 1.3888397e-03f;
|
|
fResult *= fASqr;
|
|
fResult += 4.16666418e-02f;
|
|
fResult *= fASqr;
|
|
fResult -= 4.999999963e-01f;
|
|
fResult *= fASqr;
|
|
fResult += 1.0f;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
float fast_tan(const float val)
|
|
{
|
|
float fASqr = val*val;
|
|
float fResult = 9.5168091e-03f;
|
|
fResult *= fASqr;
|
|
fResult += 2.900525e-03f;
|
|
fResult *= fASqr;
|
|
fResult += 2.45650893e-02f;
|
|
fResult *= fASqr;
|
|
fResult += 5.33740603e-02f;
|
|
fResult *= fASqr;
|
|
fResult += 1.333923995e-01f;
|
|
fResult *= fASqr;
|
|
fResult += 3.333314036e-01f;
|
|
fResult *= fASqr;
|
|
fResult += 1.0f;
|
|
fResult *= val;
|
|
|
|
return fResult;
|
|
|
|
}
|
|
|
|
float fast_asin(float val)
|
|
{
|
|
float fRoot = sqrt(1.0f-val);
|
|
float fResult = -0.0187293f;
|
|
fResult *= val;
|
|
fResult += 0.0742610f;
|
|
fResult *= val;
|
|
fResult -= 0.2121144f;
|
|
fResult *= val;
|
|
fResult += 1.5707288f;
|
|
fResult = SGD_PI_2 - fRoot*fResult;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
float fast_acos(float val)
|
|
{
|
|
float fRoot = sqrt(1.0f-val);
|
|
float fResult = -0.0187293f;
|
|
fResult *= val;
|
|
fResult += 0.0742610f;
|
|
fResult *= val;
|
|
fResult -= 0.2121144f;
|
|
fResult *= val;
|
|
fResult += 1.5707288f;
|
|
fResult *= fRoot;
|
|
|
|
return fResult;
|
|
}
|
|
|
|
float fast_atan(float val)
|
|
{
|
|
float fVSqr = val*val;
|
|
float fResult = 0.0028662257f;
|
|
fResult *= fVSqr;
|
|
fResult -= 0.0161657367f;
|
|
fResult *= fVSqr;
|
|
fResult += 0.0429096138f;
|
|
fResult *= fVSqr;
|
|
fResult -= 0.0752896400f;
|
|
fResult *= fVSqr;
|
|
fResult += 0.1065626393f;
|
|
fResult *= fVSqr;
|
|
fResult -= 0.1420889944f;
|
|
fResult *= fVSqr;
|
|
fResult += 0.1999355085f;
|
|
fResult *= fVSqr;
|
|
fResult -= 0.3333314528f;
|
|
fResult *= fVSqr;
|
|
fResult += 1.0f;
|
|
fResult *= val;
|
|
|
|
return fResult;
|
|
}
|