gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Invcos any ideas?

#43318 - iainprice - Sat May 21, 2005 10:37 pm

Hi,

I could really do with a decent inv cos...searching through a table is my only idea at the moment. Anyone got any better ones?

Cheers.

Iain.

#43319 - strager - Sat May 21, 2005 10:53 pm

All I know is that:
Code:
RAD asin(u32 val)
{
    RAD ret;

    if(abs(value) != 1)
        ret = atan(value / sqrt(1 - (value * value)));
    else
       ret = HALF_PI * sign(value);

    return(ret);
};

RAD asin(u32 val)
{
    RAD ret;

    if(abs(val) != 1)
        ret = HALF_PI - atan(val / sqrt(1 - (val * val)));
    else
       ret = PI * sign(val);

    return(ret);
};


You may do a LUT for atan and sqrt, but maybe not.

#43321 - iainprice - Sat May 21, 2005 11:02 pm

I presume one was acos and one was asin... but i still need atan for those two....

#43325 - tepples - Sun May 22, 2005 3:18 am

A lookup table followed by linear interpolation should be fast enough.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#43338 - strager - Sun May 22, 2005 11:47 am

Yup.

You might want to populate a list of atan's, and luckily there's a bios function for that (and squareroot, too). What I would do is make a little program for the GBA to call these functions, making a list in memory as you go. Then extract that block of memory using the VBA memory editor (click save, then type in the number of bytes you want, IN HEX!!!).

That's what I would do.

#43378 - mike260 - Sun May 22, 2005 9:42 pm

iainprice wrote:
I could really do with a decent inv cos...searching through a table is my only idea at the moment. Anyone got any better ones?


Here's what I normally use:

Code:
static const float ACOS_C0            =  HALF_PI;
static const float ACOS_C1            = -0.213300989f;
static const float ACOS_C2            =  0.077980478f;
static const float ACOS_C3            = -0.02164095f;

float rr_poly_acos( float x )
{
   //Worst-case error ~= 0.002 degrees
   //Function is exact at -1, 0 and 1

   if( x >= 0.0f )
   {
      const float sx = SQRT( 1.0f - x );
      const float px = ACOS_C0 + x*(ACOS_C1 + x*(ACOS_C2 + x*ACOS_C3));
      ASSERT( SANE(sx) );
      return( sx * px );
   }
   else
   {
      const float sx = SQRT( 1.0f + x );
      const float px = ACOS_C0 - x*(ACOS_C1 - x*(ACOS_C2 - x*ACOS_C3));
      ASSERT( SANE(sx) );
      return( PI - (sx * px) );
   }
}

#define ACOS(x) rr_poly_acos(x)
#define ASIN(x) (HALF_PI - ACOS(x))


It's floating-point, but it should convert over to fixed-point easily enough. Note that you can do the sqrt in parallel with calculating px, if you use the hardware sqrt.

BTW, there's a fairly easy way to create good approximations to functions using ms excel, I can post details if you're interested.

#133234 - a128 - Wed Jul 04, 2007 2:12 pm

acos from WildMagic

Code:
static int32 FastInvCos (int32 fValue)
{
    int32 fRoot = sqrtf32(floattof32(1)-fValue);
    int32 fResult = floattof32(-0.0187293f);
    fResult = mulf32(fResult,fValue);
    fResult += floattof32(0.0742610f);
    fResult = mulf32(fResult,fValue);
    fResult -= floattof32(0.2121144f);
    fResult = mulf32(fResult,fValue);
    fResult += floattof32(1.5707288f);
    fResult = mulf32(fResult,fRoot);
    return fResult;
  }

#133239 - kusma - Wed Jul 04, 2007 3:27 pm

iainprice wrote:
I could really do with a decent inv cos...searching through a table is my only idea at the moment. Anyone got any better ones?

Use the crt one? Are you really doing so many acos-calls that the performance would be a problem?

#133261 - tepples - Wed Jul 04, 2007 9:01 pm

Can you deal with using 1 KiB of RAM for a lookup table?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.