Limba has no trigonometric functions
The best way for non-hardware floating point targets is probably to use the fixed point algorithm and CORDIC.
Anthony Williams fixed point math data library provides a complete analog of the standard math library for a data type fixed
that is typically around 5 times faster than soft floating point for the same purpose. It's a C ++ library, but as long as your compiler supports C ++, this shouldn't be a problem, even if the rest of your code doesn't use C ++ special features. For the most part, all you have to do for the port code to use this library is to replace math.h with fixed.hpp and replace the keywords with float
and double
with the type fixed
.
source to share
If you don't have libraries for your system that provide sin / cos functions or in-memory lookup tables, you can create one very easily.
The following matlab function will give you a sin(x)
([0.2 * pi] range in 2 * pi / 100 increments) 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};
source to share
I don't think it makes sense to provide such a library as there are too many design and parameterization options compared to the difficulty of writing your own. I mean, none of them are very difficult, but cannot be provided as a solution for everyone.
-
parameters:
- sin / cos argument == (unsigned) vs (signed)
- short, int, float, fixed point
- range: limited (mod pi, mod 2pi)
- - the argument is radians, degrees, or whatever (e.g. 2pi == 65536 == 0)
-
meaning
- float versus fixed point versus scaled integer
- 1st quadrant only, full or extended range (no argument staging)
- both sines and cosines, or just sine
-
demands
- code size
- data size
- execution speed
- "constant" vs.
- many options are allowed.
- accuracy
- minimize minimum quadratic metric
- minimize maximum error
- minimize 1 - sin (x) ^ 2 - cos (x) ^ 2 error
-
Method
- direct a = LUT [b]
- mirroring depending on the quadrant: a = sign (b) * LUT [b ^ mirror (b)]; // conceptual formula
- CORDIC
- Polynomial of 3rd or 5th Taylor level
- added (angular) precision using two LUT tables LUTA (x) = sin (x); LUTB (x) = sin (x / 256) and formula for sum of angles
source to share