Question

The libmath on a particular embedded system does not have functions like sin and cos due to missing fp-operation unit.

Is there some library around that provides the functions via look-up tables? I do not actually need 100% reliable values.

Was it helpful?

Solution

Depending on the needed requirements for speed and precision, maybe you could create the functions needed by a simple lookup table, by writing a program to create the lookup table. Or use CORDIC.

OTHER TIPS

A better method for targets without hardware floating point is perhaps to use fixed-point and the CORDIC algorithm.

Anthony Williams' fixed-point maths library provides a complete analogue of the standard maths library for a fixed data type that is typically around 5 times faster than software floating-point on the same target. It is a C++ library, but so long as your compiler supports C++ that should not be a problem even if the rest of your code does not use C++ specific features. For the most part all you need to do to port code to use this library is to replace math.h with fixed.hpp and replace the type keywords float and double with the fixed type.

If you do not have libraries for your system providing you sin/cos functions, or a lookup tables in memory, you can create one very easily.

Next matlab function will provide you sin(x) ([0,2*pi] range with 2*pi/100 step) in a c header myheader.h :

step=2*pi/100;
x=[0:step:2*pi];
y=floor(0.5 * 65535 * sin(x));

fd=fopen('myheader.h','wt');
fprintf(fd,'int16_t y[%d]={%g',length(y),y(1));
fprintf(fd,',\n %.9g',y(2:end));
fprintf(fd,'};\n');
fclose(fd);

The header looks like this :

int16_t y[101]={0,
 2057,
 4107,
 6140,
 8149,
 10126,
 12063,
 13952,
 15786,
 17558,
 19260,
 20887,
 22431,
 23886,
 25248,
 26509,
 27667,
 28714,
 29649,
 30466,
 31164,
 31738,
 32187,
 32509,
 32703,
 32767,
 32703,
 32509,
 32187,
 31738,
 31164,
 30466,
 29649,
 28714,
 27667,
 26509,
 25248,
 23886,
 22431,
 20887,
 19260,
 17558,
 15786,
 13952,
 12063,
 10126,
 8149,
 6140,
 4107,
 2057,
 -0,
 -2057,
 -4107,
 -6140,
 -8149,
 -10126,
 -12063,
 -13952,
 -15786,
 -17558,
 -19260,
 -20887,
 -22431,
 -23886,
 -25248,
 -26509,
 -27667,
 -28714,
 -29649,
 -30466,
 -31164,
 -31738,
 -32187,
 -32509,
 -32703,
 -32768,
 -32703,
 -32509,
 -32187,
 -31738,
 -31164,
 -30466,
 -29649,
 -28714,
 -27667,
 -26509,
 -25248,
 -23886,
 -22431,
 -20887,
 -19260,
 -17558,
 -15786,
 -13952,
 -12063,
 -10126,
 -8149,
 -6140,
 -4107,
 -2057,
 -0};

Jack Ganssle has an excellent article on optimising trig for embedded systems:

http://www.ganssle.com/approx/approx.pdf

I don't think it makes sense to provide such an library, as the are too many design choices and parametrizations compared to the difficulty of writing an own. I mean none of these are very difficult, but can't be provided as fits-for-all solution.

  • the parameters:

    • argument of sin/cos == (unsigned) vs (signed)
    • short,int,float, fixed point
    • range: limited (mod pi, mod 2pi)
    • is the argument radians, degrees or something else (e.g. 2pi==65536==0)
  • the values

    • float vs. fixed point vs. scaled integer
    • 1st quadrant only, complete or extended range (no modulo reduction of argument needed)
    • both sines & cosines, or just sine
  • requirements

    • code size
    • data size
    • execution speed
      • "constant" vs.
      • a lot of variation allowed
    • precision
      • minimize some least square metric
      • minimize some maximum error
      • minimize 1 - sin(x)^2 - cos(x)^2 error
  • method

    • direct a=LUT[b]
    • mirroring depending on quadrant: a=sign(b)*LUT[ b ^ mirror(b)]; // conceptual formula
    • CORDIC
    • 3rd or 5th degree Taylor polynomial
    • added (angular) precision using two LUT tables LUTA(x)=sin(x); LUTB(x)=sin(x/256) and formula for sum of angles
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top