I have to write Sine and Cos Math functions but without using the standard library functions from math.h file.
Because, I dont want to write these functions with integer data type. But library functions support floating point.
I tried to do some research, but most of the algorithms are based on floating point itself (using Taylor series, horner method).
Can any one please provide sample code for Sin, Cos algorithms based on Integers.
I'm using Codewarrior compiler v2.7 for MPC5604P.
Solved! Go to Solution.
Taylor series are infinite!. Dropping the most and leaving just few nonzero coefficients (in general) gives very poor accuracy. There are methods to optimize series order by slightly tuning series coefficients and greatly improving resulting accuracy. Google for Minimax Polynomial etc.
Now about your code.
1) ss16_tmp_Angle_In_Rad = 32767*(((s16_tmp_Angle_In_Deg) * pi)/180);
Is pi floating point number here? So why not to just use FP sin()? If indeed integer, then you should first do all multiplies, and divide after all mulls are done. As you may know integer divide drops remainder. Dividing at the end should give you more procise result.
2) 90degs is pi/2, which is above 1. pi/2 won't fit signed /32768 integer fraction! You need to use long integers.
3) I'm not sure if you know it, but to multiply two /32768 integer fructions you should multiply them first (producing long integer), and then divide the product by 32768. All those 32bit calculations can take compareable time to what you may have using standard sin().
See attached two excel files, isin.xls for /32768 fractions and isin8.xls for /256 fractions. To emulate integer math, I was using excell INT() function. Series coefficient are optimized to produce smaller error. BTW /256 sine still is good enough with just two series members, s7=0. So go ahead implementing it all.
Hello,
You do not mention the angular resolution that you require? I assume that the return value could be presented as a signed 16-bit binary fraction.
One alternative approach might utilise a look-up table to represent one quadrant of a sinusoid, with linear interpolation used to increase the angular resolution. The first quadrant angle may be easily derived from an arbitrary angle, and the sign determined, for both sine and cosine functions. Since the binary fraction does not incorporate the values +1 and -1, these might need to be treated as special cases.
For this approach, it might be simpler to base your input on degree units, rather than radians. With a one degree table increment, the table size would be 90 words. For the linear interpolation process, you might have an 8-bit value as the fractional part of the angle input.
Regards,
Mac
Dear Mac, Sorry the late reply.
1. I would like to have angular resolution of -pi to +pi (-180deg to 180 deg)
2. And return value of my function would be unsigned short (Frac16)
But, I'm not quite familiar in this type of coding (i.e. Sine function and also converting the code from floating point type to support integer type).. I attached my sample code here, kindly check it please.
Thanks
You might be better off with using the tabular method bigmac suggested. Your Taylor series expansion looks like it'll will really suffer from truncation errors.
Oh, and I'm not sure if your compiler supports modulus operations or not...
Actually, due to memory issues, I prefer to follow Taylor series for my function instead of Look up table.
Infact, it is the requirement for me to use Taylor series method.
I update something in my sample code in the attachment.
Kindly guide me please.
Hm, don't you have spare 720 bytes of flash on MPC5604P for full sin table (360 degs * 2bytes)?
Hi Kef,
Thanks alot for your help.. Your excel sheet helped me to implement the Sin, Cos functions properly to my requirement.
I understand now, how to scale the normal sine/cos function for the integer data type..
i.e. Sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! ......-
can be scaled as x-((x/32768)^3)/3! + ((x/32768)^5)/5! - ((x/32768)^7)/7! ..........
Also, the following website gave me valuable information... it might be helpful for the guys who wants to implement Trig functions.
http://mathonweb.com/help_ebook/html/algorithms.htm
Thanks for your help.
Have a nice weekend.
I'm glad it helped.
Not at all. Formula doesn't look right. But those /32768 after each multiplication are required to preserve fixed point format of 15bits fractional part. You translate real numbers X to integer fraction x doing x = X*32768. Now with integer fractions you do x+x for X+X, x-x for X-X. But you need to do x*x/32768 for X*X and x*32768/x for X/X.
Example that should explain it a bit. What if you use 1000 instead of 32768 factor. You convert real 0.1 to integer 100, 0.01 to integer 10 etc. So product 0.1*0.1=0.01 should translate to 100*100=10, while in reality you get 100*100=10000. You need to divide product by 1000 to get right fixed point result.
Thanks alot for the correction Kef. I understand it now !
Hello,
Using the truncated series method, per the supplied link, it seems possible to slightly rearrange the expressions to simplify the processing.
The first three terms of the sine series can alternatively be expressed as:
.
x*( 1 - (x*x)*( 1 - (x*x)/20 )/6 )
.
and the first four terms of the cosine series can be expressed as:
.
1 - (x*x)*( 1 - (x*x)*( 1 - (x*x)/30 )/12 )/2
.
The following code appears to produce the expected result for fractional integer arithmetic.
#define P4 25736L // pi / 4 * 32768// Integer sine function for angles <= 45 degreesint sin_( int deg){ long xrad, sxr; long a = 32768; long b = 196608; // 6 * a xrad = deg * P4 / 45; // Convert to radians sxr = xrad * xrad / a; return ((int)(xrad * (a - sxr * (a - sxr / 20) / b) / a));}// Integer cosine function for angles <= 45 degreesint cos_( int deg){ long xrad, sxr; long a = 32768; long b = 65536; // 2 * a long c = 393216; // 12 * a if (deg == 0) return (int)(a - 1); // Maximum limit for signed 16-bit xrad = deg * P4 / 45; // Convert to radians sxr = xrad * xrad / a; return ((int)(a - sxr * (a - sxr * (a - sxr / 30) / c) / b));}
Regards,
Mac
Taylor series are infinite!. Dropping the most and leaving just few nonzero coefficients (in general) gives very poor accuracy. There are methods to optimize series order by slightly tuning series coefficients and greatly improving resulting accuracy. Google for Minimax Polynomial etc.
Now about your code.
1) ss16_tmp_Angle_In_Rad = 32767*(((s16_tmp_Angle_In_Deg) * pi)/180);
Is pi floating point number here? So why not to just use FP sin()? If indeed integer, then you should first do all multiplies, and divide after all mulls are done. As you may know integer divide drops remainder. Dividing at the end should give you more procise result.
2) 90degs is pi/2, which is above 1. pi/2 won't fit signed /32768 integer fraction! You need to use long integers.
3) I'm not sure if you know it, but to multiply two /32768 integer fructions you should multiply them first (producing long integer), and then divide the product by 32768. All those 32bit calculations can take compareable time to what you may have using standard sin().
See attached two excel files, isin.xls for /32768 fractions and isin8.xls for /256 fractions. To emulate integer math, I was using excell INT() function. Series coefficient are optimized to produce smaller error. BTW /256 sine still is good enough with just two series members, s7=0. So go ahead implementing it all.