cos(x) =?

Discussion in 'Mathematics and Physics' started by Ian Rogers, Jun 27, 2017.

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK
I have two functions in a piece of code..

x = cos(a);
y = sin(a);

When using degrees I normally just go.

x = cos(a);
y = 1 - x;

Joined:
Jul 10, 2011
Messages:
9,289
Likes:
1,222
Location:
Cardiff, Wales
Once x is calculated the relationship with y still holds.

Last edited: Jun 27, 2017

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK
Yes.. I know...

I don't want to use two trig functions so I will deduce sin(x) from the answer of cos(x)..

4. DaveNew Member

Joined:
Jan 12, 1997
Messages:
-
Likes:
0

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK

For the time being, I've cranked up the micro speed to 32Mhz... It has allowed me to run with two trig functions.... I'll see if I can find an alternate sin ~ cosine routine... Currently 14mS to create an Arc... I need 6 of then so around 84mS is a tad too much, but! Hey ho!

Joined:
Sep 11, 2004
Messages:
6,356
Likes:
586
Location:
ONLINE
Ian, are you saying that sin(a) = 1 - cos(a) ?
I think that you are a bit off the mark there.

The correct relationship is sin^2 + cos^2 = 1

Which would give y = sqrt(1 - x^2) using your notation.

JimB

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK
Yep! Found that out in radians... sin(a) = cos(a + PI/2)... A tad crap for me...

I found a super duper fast routine here!!! But its only a small bit faster than XC8's builtin..

I thought that because cos(30) = 0.86 and sin(60) = 0.86, "Senior moment", it was linear back to front!!

What I do when I use cos for sin is.. cos (30) = sin(90-30) which is correct!! But using radians turned me upside down.

8. RatchitWell-Known Member

Joined:
Mar 12, 2008
Messages:
1,948
Likes:
83

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK
I had a quick look through... Its in pascal for the x86 system... A couple of issues.. Namely A) its for 32 bit machine and B) it uses "fmul" and most PC's have a floating point unit... I would like to see how fast it runs turning of the hardware FPU and using the software FPU.

But for my PC ( Lazarus ) projects... Thanks for that!

Joined:
Sep 7, 2008
Messages:
11,042
Likes:
959
Location:
NJ
Hi,

Yes i had to look twice when i saw that 1-cos(a) was somehow coming out to sin(a)
And yes, rads=degrees*pi/180 so a formula like:
x=cos(a)

in degrees is just:
x=cos(a*pi/180)

The two best forms are probably these two:
x=r*cos(a)
y=r*sin(a)

combined with the circle of radius 'r':
r^2=x^2+y^2

and after substitution of x and y:
r^2=(r*cos(a))^2+(r*sin(a))^2
r^2=r^2*cos(a)^2+r^2*sin(a)^2
r^2=r^2*(cos(a)^2+sin(a)^2)
and using the identity cos(a)^2+sin(a)^2=1 we end up with:
r^2=r^2*1
so:
r^2=r^2

and we've proved the identity.

So we can solve for sin(a)^2 and get:
sin(a)^2=1-cos(a)^2

and taking the square root of both sides we get:
abs(sin(a))=sqrt(1-cos(a)^2)

and so we have to split this into two forms showing principle angles:
sin(a)=sqrt(1-cos(a)^2), for pi<=a<=0 (eg from a=0 to pi)
sin(a)=-sqrt(1-cos(a)^2), for -pi<=a<=0 (eg from a=0 to -pi)

Also note that sin(a) may be more accurate than using the calculation on some angles, especially those close to either 90 degrees or 0 degrees (one of the axes).

Last edited: Jul 3, 2017

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK
So MrAl to answer my question

I have a point x,y.. I rotate the point around a central fixed point..
This means I need a vertical component ie... sin(x)
And a horizontal component namely cos(x)

I need to work out cos(x) without trig... Let me explain..

cos(20) = 0.9396... and sin(20) = 0.342... But! sin(90-20) = 0.9396... I "stupidly" assumed that I could use only one trig function.. BUT!! I soon realised that I cannot make the changes after the trig the alterations have to be made before the trig function... I just wondered if it were possible to only use 1 trig function for sin and cos

12. RatchitWell-Known Member

Joined:
Mar 12, 2008
Messages:
1,948
Likes:
83
Here you go, Cos{x} without trig once you know the single trig Sin[x]. To find the cosine after the sine is known, subtract from 1, the square of the sine, the extract the square root for the cosine as shown below.

t

Ratch

Attached Files:

• Rogers.JPG
File size:
14.5 KB
Views:
34

Joined:
Sep 7, 2008
Messages:
11,042
Likes:
959
Location:
NJ
Hello again,

However, there are also the approxmations as sin(x) can be approximated in many ways.
For example sin(x) can be approximated one way as:
sin(x)=(5880*x-620*x^3)/(11*x^4+360*x^2+5880)

A simple 4 term Taylor series gets you there also:
sin(x)=x-x^3/6+x^5/120-x^7/5040

or:
cos(x)=1-x^2/2+x^4/24-x^6/720+x^8/40320

These are best between 0 and pi/2.

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK
I came across this.... As I am working on a small 128x128 screen it will do the job.

It comes from "Ye olde spectrum" but it is very fast...

I post it here for others... it only uses 45 point lookup.
Code (c):

const char sintable[] ={
0,9,18,27,35,44,53,62,
70,79,87,96,104,112,120,127,
135,143,150,157,164,171,177,183,
190,195,201,206,211,216,221,225,
229,233,236,240,243,245,247,249,
251,253,254,254,255,255};

double mycos(double deg)
{
return mysin(90-deg);
}
double mysin(double deg)
{
int esti, diff;
while(deg>360)
deg-=360;
while(deg<0)
deg+=360;
if(deg>180)
{
deg-=180;
}
else
if(deg>90) deg = 180-deg;
deg/=2;
diff = (int)deg;
deg = deg - diff;
esti = sintable[diff];
diff = sintable[diff+1] - esti;
deg *= diff;
deg += esti;
}

Its at least 5 times faster than the math library!!

Joined:
Sep 7, 2008
Messages:
11,042
Likes:
959
Location:
NJ
Hi Ian,

Looks very interesting, i'll have to try it out a little later.

Maybe you could help me find an approximation i posted a while back for sin(x)?
I cant seem to find it now.
I posted on this site but not sure if it was in math or not now.

Joined:
Mar 28, 2011
Messages:
9,251
Likes:
911
Location:
Rochdale UK
XC8 uses approximation, but for what I need its over the top... I am working to int precision so the above is overkill let alone the successive one ..

Here is XC8's sin()..
Code (c):

double sin(double f)
{
const static double coeff_a[] =
{
207823.68416961012,
-76586.415638846949,
7064.1360814006881,
-237.85932457812158,
2.8078274176220686
};
const static double coeff_b[] =
{
132304.66650864931,
5651.6867953169177,
108.99981103712905,
1.0
};
double x2, y;
unsigned char sgn;
#ifdef i8086
if(_use8087)
return _sin87(f);
#endif
sgn = 0;
if(f < 0.0) {
f = -f;
sgn = 1;
}
f *= 1.0/TWO_PI;
f -= floor(f);
f *= 4.0;
if(f > 2.0) {
f -= 2.0;
sgn = !sgn;
}
if( f > 1.0)
f = 2.0 - f;
x2 = f * f;
y = eval_poly(x2, coeff_b, 3);
f *= eval_poly(x2, coeff_a, 4) / y;
if(sgn)
return -f;
return f;
}

double eval_poly(double x, const double * d, int n)
{
double res;
res = d[n];
while(n)
res = x * res + d[--n];
return res;
}

The eval_poly is the successive part..

17. RatchitWell-Known Member

Joined:
Mar 12, 2008
Messages:
1,948
Likes:
83
Ian Rogers,
First of all, I would use a look-up table. It can be one degree increments from 0-90. Or, it can be 2 degree increments or more. The same 90° table can be used for the cos because cos(70) is sin(20). The same table can also be used for 0-360 be adjusting the sign of the sines. Once the angle is determined to the nearest degree, the incremental part can be determined. Then use the incremental Taylor series to calculate the sin of the total angle. Suppose we want to calculate the sin of 1.5 degrees. The integer degree part call "a" and the incremental part call "h". The incremental Taylor series is

Applying the above equation and converting a=1 degree and h=0.5 degree to radians, the sin of 1.5 degrees is easily found to be 0.0261769. Notice that successive derivatives of the sin alternate between the sin and cos. Fewer terms or a smaller look-up table can be used if lower precision is acceptable. Observe that the sin changes the fastest at 0 and pi radians, so the precision will be less at that area of the sin.

Ratch