Quote:
|
Originally Posted by mtrawls
We didn't use trig in our final implementation ... but in testing we did consider it, and also decided on the CORDIC algorithm. There is an added advantage of CORDIC that your library currently doesn't utilize -- it can compute both the sin and cosine at the same time (which you do, but then you throw one of them away). For our trig needs, anyway, we needed the sin and cos of the same angles.
Implementing this in a math library (admittedly more general than our custom implementation), would be interesting conceptually. Maybe create a structure called angle....
|
I have not really looked into CORDIC before. It's interesting that it computes both sine and cosine at the same time. And I like your idea of making them both available. I think I would probably choose an approach where I just save both values, and then the next time a sine or cosine is called for, check to see if the angle is the same as last time. If it is, then I could just return the previous value. Granted there is something to to say for your idea of the struct, because it would be simple that way, to save the trig functions for a few commonly used angles.
Be that as it may, here's my suggestion of an implementation:
Code:
typedef enum {wantsSin, wantsCos} WhichFunc;
short long cordic(short long theAngle, WhichFunc theRequestedFunction)
{
static char firstTime = 1;
static short long prevAngle;
static short long prevSin;
static short long prevCos;
unsigned char i;
short long X = K, Y = 0, t = theAngle;
short long dx, dy;
// If this is the first time the function has been called, or if the
// requested angle is different than the last time, then go ahead and
// calculate the sine and cosine, otherwise we can skip the calculations,
// and just return the value calculated last time.
if (firstTime || (theAngle != prevAngle)) {
if ((long) abs((long)theAngle) > 4194304)
t = (short long) sgn((long) theAngle) * (8388608 - (short long) abs(theAngle));
for (i = 0; i < 23; i++) {
dx = sgn((long) X) * ((unsigned short long) abs((long) X) >> i);
dy = sgn((long) Y) * ((unsigned short long) abs((long) Y) >> i);
X -= (t > 0) ? dy : -dy;
Y += (t > 0) ? dx : -dx;
t -= (t > 0) ? e[i] : -e[i];
} // for
if (abs((long) theAngle) > 4194304) X = -X;
firstTime = 0;
prevAngle = theAngle;
prevSin = Y;
prevCos = X;
} // if (firstTime ...
if (theRequestedFunction == wantsSin)
return prevSin;
else
return prevCos;
}
short long sin(short long theAngle)
{
return cordic(theAngle, wantsSin);
}
short long cos(short long theAngle)
{
return cordic(theAngle, wantsCos);
}
Note I took some liberties with team 296's code to suit my own personal preferences. You can take it or leave it:
- I unrolled the nested ::gasp:: ternary operators in the return statement to make it more readable.
- I changed the name of the "ang" parameter to theAngle, so that someone unfamiliar with the code won't have to stop and think "Ang? What's that? Anger? Angst? Angstrom? Automatic Number Generator?" (Yeah, I know it's FAIRLY obvious from the context, but I prfr rdg fl wrds nstd f abbrvs. cn u dg it?)
- I changed the name of the second parameter of the cordic() routine (again so it's more obvious what the parameter is used for) and I made it an enum so that you never have to wonder whether 0 or 1 means sine or cosine.
- I added a couple of end brace comments so it's easier to match up opening and closing braces.
- I moved the cordic() function in front of sin() and cos(), so I wouldn't need a prototype for cordic().