fixed.cpp

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////
00002 //
00003 //  Fixed Point Math Class
00004 //
00005 //////////////////////////////////////////////////////////////////////////
00006 //
00007 //  Released under GNU license
00008 //              Erik H Gawtry
00009 //                      July, 2005      Version 1.0
00010 //
00011 //
00012 //  Algorythms borrowed from:
00013 //              Andrew Ryder, 11 September 2001
00014 //      Joseph Hall, Unknown Date
00015 //
00016 //
00017 //////////////////////////////////////////////////////////////////////////
00018 //
00019 // Written for doing fixed point math on DSP processors
00020 //
00021 //////////////////////////////////////////////////////////////////////////
00022 
00023 #include "fixed.h"
00024 #include <math.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <limits.h>
00028 #include <common/DefinesAssert.h>
00029 #include <common/DefinesString.h>
00030 #include <common/Logger.h>
00031 
00032 #define _XPI      31415 // 3.1415926535897932384626433832795
00033 fixed fixed::XPI = fixed(true,_XPI);
00034 #define _X2PI     62831 // 6.283185307179586476925286766559
00035 fixed fixed::X2PI =    fixed(true,_X2PI);
00036 #define _XPIO2    15707 // 1.5707963267948966192313216916398
00037 fixed fixed::XPIO2 =   fixed(true,_XPIO2);
00038 #define _XPIO4    7853 // 0.78539816339744830961566084581988
00039 #define XPIO4    fixed(true, _XPIO4)
00040 #define _XLN_E    27182 // 2.71828182845904523536
00041 #define XLN_E    fixed(true,_XLN_E)
00042 #define _XLN_10   23025 // 2.30258509299404568402
00043 #define XLN_10   fixed(true,_XLN_10)
00044 
00045 fixed fixed::MAX_FIXED(true, INT_MAX); // 32 bit
00046 
00047 inline int fixed_internal_mult(int a, int b)
00048 {
00049         int c = 0;
00050         if (sizeof(long) == 8)
00051         {
00052                 c = (int)((((long)a)*((long)b))/FIXED_RESOLUTION);
00053         }
00054         else if (sizeof(long long) == 8)
00055         {
00056                 c = (int)((((long long)a)*((long long)b))/FIXED_RESOLUTION);
00057         }
00058         return c;
00059 }
00060 
00061 inline int fixed_internal_div(int a, int b)
00062 {
00063         if(b == 0) return 0xFFFFFFF;
00064 
00065         int c = 0;
00066         if (sizeof(long) == 8)
00067         {
00068                 c = (int)((((long)a)*((long)FIXED_RESOLUTION))/b);
00069         }
00070         else if (sizeof(long long) == 8)
00071         {
00072                 c = (int)((((long long)a)*((long long)FIXED_RESOLUTION))/b);
00073         }
00074         return c;
00075 }
00076 
00077 fixed::fixed(const char *nVal)
00078 {
00079         if (strlen(nVal) > 12)
00080         {
00081                 Logger::log(S3D::formatStringBuffer("Warning: Ignoring fixed string conversion of %s", nVal));
00082 
00083                 m_nVal = 0;
00084                 return;
00085         }
00086 
00087         char i[15];
00088         char f[15];
00089 
00090         int ip = 0;
00091         int fp = 0;
00092         bool fract = false;
00093         bool neg = false;
00094         for (const char *c=nVal; *c; c++)
00095         {
00096                 if (*c == '.') fract = true;
00097                 else if (*c == '-') neg = true;
00098                 else 
00099                 {
00100                         if (fract) f[fp++] = *c;
00101                         else i[ip++] = *c;
00102                 }
00103         }
00104 
00105         for (; fp<4; fp++)
00106         {
00107                 f[fp] = '0';
00108         }
00109         i[ip] = '\0';
00110         f[fp] = '\0';
00111         DIALOG_ASSERT(ip < 15 && fp < 15);
00112 
00113         int ipa = atoi(i);
00114         int fpa = atoi(f);
00115 
00116         m_nVal = ipa * FIXED_RESOLUTION + fpa;
00117         if (neg) m_nVal =- m_nVal;
00118 }
00119 
00120 const char *fixed::asString()
00121 {
00122         static char result[15];
00123         int r = 0;
00124 
00125         char buffer[15];
00126         if (m_nVal < 0) 
00127         {
00128                 snprintf(buffer, 15, "%i", -m_nVal);
00129                 result[r++] = '-';
00130         }
00131         else 
00132         {
00133                 snprintf(buffer, 15, "%i", m_nVal);
00134         }
00135         int len = strlen(buffer);
00136 
00137         if (len <= 4)
00138         {
00139                 result[r++] = '0';
00140                 result[r++] = '.';
00141                 for (int i=len; i<4; i++)
00142                 {
00143                         result[r++] = '0';
00144                 }
00145                 for (int i=0; i<len; i++)
00146                 {
00147                         result[r++] = buffer[i];
00148                 }
00149         }
00150         else
00151         {
00152                 for (int i=0; i<len-4; i++)
00153                 {
00154                         result[r++] = buffer[i];
00155                 }
00156                 result[r++] = '.';
00157                 for (int i=len-4; i<len; i++)
00158                 {
00159                         result[r++] = buffer[i];
00160                 }
00161         }
00162 
00163         result[r++] = '\0';
00164         DIALOG_ASSERT(r < 15);
00165 
00166         return result;
00167 }
00168 
00169 fixed fixed::operator*(fixed b)
00170 {
00171         return fixed(true, fixed_internal_mult(m_nVal, b.m_nVal));
00172 }
00173 
00174 fixed fixed::operator/(fixed b)
00175 {
00176         return fixed(true, fixed_internal_div(m_nVal, b.m_nVal));
00177 }
00178 
00179 fixed fixed::operator*=(fixed b)
00180 {
00181         m_nVal = fixed_internal_mult(m_nVal, b.m_nVal);
00182         return *this;
00183 }
00184 
00185 fixed fixed::operator/=(fixed b)
00186 {
00187         m_nVal = fixed_internal_div(m_nVal, b.m_nVal);
00188         return *this;
00189 }
00190 
00191 #define sqrt_step(shift) \
00192     if((0x40000000l >> shift) + root <= value)          \
00193     {                                                   \
00194         value -= (0x40000000l >> shift) + root;         \
00195         root = (root >> 1) | (0x40000000l >> shift);    \
00196     }                                                   \
00197     else                                                \
00198     {                                                   \
00199         root = root >> 1;                               \
00200     }
00201 
00202 static int iSqrt(int value)
00203 {
00204     int root = 0;
00205 
00206     sqrt_step( 0);
00207     sqrt_step( 2);
00208     sqrt_step( 4);
00209     sqrt_step( 6);
00210     sqrt_step( 8);
00211     sqrt_step(10);
00212     sqrt_step(12);
00213     sqrt_step(14);
00214     sqrt_step(16);
00215     sqrt_step(18);
00216     sqrt_step(20);
00217     sqrt_step(22);
00218     sqrt_step(24);
00219     sqrt_step(26);
00220     sqrt_step(28);
00221     sqrt_step(30);
00222 
00223     // round to the nearest integer, cuts max error in half
00224 
00225     if(root < value)
00226     {
00227         ++root;
00228     }
00229 
00230     return root;
00231 }
00232 
00233 fixed absx( fixed p_Base )
00234 {
00235         if( p_Base < fixed(0) ) return -p_Base;
00236         return p_Base;
00237 }
00238 /*
00239                      (x^h) - 1
00240    ln(x)  =   lim    -------      
00241              h -> 0     h
00242 
00243 */
00244 
00245 static fixed iLog2( fixed p_Base )
00246 {   
00247     fixed w = 0;
00248         fixed y = 0;
00249         fixed z = 0;
00250         fixed num = 1;
00251         fixed dec = 0;
00252 
00253         if( p_Base == fixed(1) )
00254                 return 0;
00255 
00256         for( dec=fixed(0) ; absx( p_Base ) >= fixed(2) ; ++dec )
00257                 p_Base /= XLN_E;
00258 
00259         p_Base -= fixed(1);
00260         z = p_Base;
00261         y = p_Base;
00262         w = 1;
00263 
00264         while( y != y + w )
00265                 y += ( w = ( z = fixed(0) - ( z * p_Base ) ) / ( fixed(num) += fixed(1) ) );
00266 
00267         return y + fixed(dec);
00268 }
00269 
00270 /*
00271         calculate the exponential function using the following series :
00272 
00273                           x^2     x^3     x^4     x^5
00274         exp(x) == 1  +  x  +  ---  +  ---  +  ---  +  ---  ...
00275                            2!      3!      4!      5!
00276 
00277 */
00278 
00279 static fixed iExp2(fixed p_Base)
00280 {
00281         fixed w;
00282         fixed y;
00283         fixed num;
00284 
00285         for( w=fixed(1), y=fixed(1), num=fixed(1) ; y != y+w ; ++num )
00286                 y += ( w *= p_Base / fixed(num) );
00287 
00288         return y;
00289 }
00290 
00291 static fixed ipow( fixed p_Base, fixed p_Power )
00292 {
00293         if( p_Base < fixed(0) && p_Power%2 != fixed(0) )
00294                 return - iExp2( (p_Power * iLog2( -p_Base )) );
00295         else
00296                 return iExp2( (p_Power * iLog2(absx( p_Base ))) );
00297 }
00298 
00299 static fixed ilog10( fixed p_Base )
00300 {
00301         return iLog2( p_Base ) / XLN_10;
00302 }
00303 
00304 fixed fixed::sqrt()
00305 {
00306         int val = iSqrt(m_nVal);
00307         val *= 100;
00308         return fixed(true, val);
00309 }
00310 
00311 fixed sqrtx(fixed fixedVal)
00312 {
00313         return fixedVal.sqrt();
00314 }
00315 
00316 fixed fixed::pow(fixed fixedPower)
00317 {
00318         return ipow(*this, fixedPower);
00319 }
00320 
00321 fixed powx(fixed fixedVal, fixed fixedPower)
00322 {
00323         return fixedVal.pow(fixedPower);
00324 }
00325 
00326 fixed fixed::exp()
00327 {
00328         return iExp2(*this);
00329 }
00330 
00331 fixed expx(fixed fixedVal)
00332 {
00333         return fixedVal.exp();
00334 }
00335 
00336 fixed fixed::log10()
00337 {
00338         return ilog10(*this);
00339 }
00340 
00341 fixed log10x(fixed fixedVal)
00342 {
00343         return fixedVal.log10();
00344 }
00345 
00346 fixed fixed::log()
00347 {
00348         return iLog2(*this);
00349 /*
00350         Calculate the POW function by calling EXP :
00351 
00352                   Y      A                 
00353                  X   =  e    where A = Y * log(X)
00354 */
00355 }
00356 
00357 fixed logx(fixed fixedVal)
00358 {
00359         return fixedVal.log();
00360 }
00361 
00362 fixed floorx(fixed fixedVal)
00363 {
00364         return fixedVal.floor();
00365 }
00366 
00367 fixed ceilx(fixed fixedVal)
00368 {
00369         return fixedVal.ceil();
00370 }
00371 
00372 //
00373 // Taylor Algorythm
00374 // x - x^3/3! + x^5/5! - x^7/7! + x^9/9! ........    
00375 //
00376 // Note: Make xresult a float to get more precision
00377 //
00378 // Only accurate from -PI/2 to PI/2
00379 
00380 static fixed _sinx(fixed x)
00381 {
00382         fixed xpwr;
00383         int xftl;
00384         fixed xresult;
00385         bool positive;
00386 
00387         xresult = 0;
00388         xpwr = x;
00389         xftl = 1;
00390         positive = true;
00391 
00392         // Note: 12! largest for int
00393         for(int i = 1; i < 7; i+=2)
00394         {
00395                 if( positive )
00396                         xresult += (xpwr/fixed(xftl));
00397                 else
00398                         xresult -= (xpwr/fixed(xftl));
00399 
00400                 xpwr *= x;
00401                 xpwr *= x;
00402                 xftl *= i+1;
00403                 xftl *= i+2;
00404                 positive = !positive;
00405         }
00406 
00407         return xresult;
00408 }
00409 
00410 fixed fixed::sin()
00411 {
00412         fixed xresult;
00413         bool bBottom = false;
00414         static fixed xPI = XPI;
00415         static fixed x2PI = X2PI;
00416         static fixed xPIO2 = XPIO2;
00417 
00418         fixed x(true, m_nVal%_X2PI);
00419         if( x < fixed(0) )
00420                 x += x2PI;
00421 
00422         if( x > xPI )
00423         {
00424                 bBottom = true;
00425                 x -= xPI;
00426         }
00427 
00428         if( x <= xPIO2 )
00429                 xresult = _sinx(x);
00430         else
00431                 xresult = _sinx(xPIO2-(x-xPIO2));
00432 
00433         if( bBottom )
00434                 return -xresult;
00435 
00436         return xresult;
00437 }
00438 
00439 fixed sinx(fixed x)
00440 {
00441         return x.sin();
00442 }
00443 
00444 fixed fixed::acos()
00445 {
00446         return fixed(0);
00447 }
00448 
00449 fixed fixed::cos()
00450 {
00451         fixed xresult;
00452         bool bBottom = false;
00453         static fixed xPI = XPI;
00454         static fixed x2PI = X2PI;
00455         static fixed xPIO2 = XPIO2;
00456 
00457         fixed x(true, (m_nVal+_XPIO2)%_X2PI);
00458         if( x < fixed(0) )
00459                 x += x2PI;
00460 
00461         if( x > xPI )
00462         {
00463                 bBottom = true;
00464                 x -= xPI;
00465         }
00466 
00467         if( x <= xPIO2 )
00468                 xresult = _sinx(x);
00469         else
00470                 xresult = _sinx(xPIO2-(x-xPIO2));
00471 
00472         if( bBottom )
00473                 return -xresult;
00474 
00475         return xresult;
00476 }
00477 
00478 fixed cosx(fixed x)
00479 {
00480         return x.cos();
00481 }
00482 
00483 fixed fixed::tan()
00484 {
00485         return sin()/cos();
00486 }
00487 
00488 fixed tanx(fixed x)
00489 {
00490         return x.tan();
00491 }
00492 
00493 fixed fixed::fromFloat(float flt)
00494 {
00495         fixed result;
00496         result.m_nVal = int(flt * FIXED_RESOLUTION_FLOAT);
00497         return result;
00498 }
00499 
00500 static fixed CON1(true, 2679);  /* 2 - sqrt(3)                  */
00501 static fixed ROOT_3M1(true, 7321);      /* sqrt(3) - 1                  */
00502 static fixed ROOT_3(true, 17321); /* square root of 3 */
00503 
00504 static fixed p0 = fixed(true, -136887);
00505 static fixed p1 = fixed(true, -205058);
00506 static fixed p2 = fixed(true, -84946);
00507 static fixed p3 = fixed(true, -8375);
00508 static fixed q0 = fixed(true,  410663);
00509 static fixed q1 = fixed(true,  861573);
00510 static fixed q2 = fixed(true,  595784);
00511 static fixed q3 = fixed(true,  150240);
00512 
00513 static fixed at[] = 
00514 {
00515     0,
00516     fixed(true, 5235),          /* pi / 6                       */
00517         fixed::XPIO2,                   /* pi / 2                       */
00518     fixed(true, 10472)          /* pi / 3                       */
00519 };
00520 
00521 static fixed _atanx(fixed f, int n)
00522 {
00523     fixed g, q, r;
00524 
00525     if (f > CON1) 
00526         {
00527                 f = (((ROOT_3M1 * f - fixed(true, 5000)) - fixed(true, 5000)) + f) / (ROOT_3 + f);
00528                 n++;
00529     }
00530         {
00531                 g = f * f;
00532                 q = (((g + q3)*g + q2)*g + q1)*g + q0;
00533                 r = (((p3*g + p2)*g + p1)*g + p0)*g / q;
00534                 f = f + f * r;
00535     }
00536 
00537         if (n > 1) f = -f;
00538     return(f + at[n]);
00539 }
00540 
00541 fixed atanx(fixed x)
00542 {
00543     fixed f = x < 0 ? -x : x;
00544     if (f > 1) f = _atanx(fixed(1) / f, 2);
00545     else f = _atanx(f, 0);
00546 
00547     return(x < fixed(0) ? -f : f);
00548 }
00549 
00550 fixed atan2x(fixed v, fixed u)
00551 {
00552         fixed f;
00553         fixed av = v < 0 ? -v : v;
00554         fixed au = u < 0 ? -u : u;
00555 
00556         if (u != 0) 
00557         {
00558                 if (av > au) 
00559                 {
00560                         if ((f = au / av) == 0) f = fixed::XPIO2;
00561                         else f = _atanx(f, 2);
00562                 }
00563                 else 
00564                 {
00565                         if ((f = av / au) == 0) f = 0;
00566                         else f = _atanx(f, 0);
00567                 }
00568         }
00569         else 
00570         {
00571                 if (v != 0) f = fixed::XPIO2;
00572                 else 
00573                 {
00574                         //cmemsg(FP_ATAN, &v);
00575                         f = 0;
00576                 }
00577         }
00578         if (u < 0) f = fixed::XPI - f;
00579 
00580         return(v < 0 ? -f : f);
00581 }

Generated on Mon Feb 16 15:14:48 2009 for Scorched3D by  doxygen 1.5.3