Answered by:
Math.Sin, Math.Cos issue with trigonometric thumb rule.
Question

The thumb rule of trigonometry is sin(degree) * sin(degree) + cos(degree) * cos(degree) = 1,
for the following example i am not getting those results.
I am using the value 0.71001282198650217
double deg = 0.71001282198650217; double result = System.Math.Sin(deg) * System.Math.Sin(deg) + System.Math.Cos(deg) * System.Math.Cos(deg); // here result should be 1.0, but i am getting 0.99999999999999989 Console.WriteLine(result.Tostring());
which is wrong completely.
Can anybody explain me how i can get 1.0 as the result here?
 Edited by Naveen L Friday, May 4, 2012 1:02 PM marked code.
Friday, May 4, 2012 12:58 PM
Answers

Some comments which you can cheerfully ignore.
First, as far as I know Math calculations use IEEE arithmetic so are correct to 15 decimal places. You won't get any more accurate than that. For a particular formula you might get much less, depending on how you arrange the calculations. That's a topic in numerical analysis.
Secondly, if you have a formula that contains "sin(a)*sin(a) + cos(a)*cos(a)" then simply replace it with 1, since that is true for all values of a. I suspect that the formula you refer to has something like "sin(a)*sin(b) + cos(a)*cos(b)". In that case of course you can't replace with 1, but there might be a rearrangement (perhaps using tan or some other trig function) that is numerically better behaved. But you still won't get better than 15 d.p.
Thirdly, if the built in sin and cos are not accurate enough you could of course write your own functions e.g. as a series sum (which I suspect is what Math.Sin does).
Regards David R

The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
Objectoriented programming offers a sustainable way to write spaghetti code.  Paul Graham.
Every program eventually becomes rococo, and then rubble.  Alan Perlis
The only valid measurement of code quality: WTFs/minute. Proposed as answer by servy42 Friday, May 4, 2012 2:40 PM
 Marked as answer by Mike Dos Zhang Thursday, May 10, 2012 10:47 AM
Friday, May 4, 2012 2:31 PM 
@Scotty & Ahmed
The problem can't just be fixed by rounding the result. Clearly the entire design of the program is based around the fact that doubles have infinite precision, and they don't. The program itself will likely need to be more fundamentally altered. Also keep in mind that if you have enough computations you can actually be off by more than one unit of whatever digit you round to, so just rounding can make things much worse.
@Naveen
Doubles don't have infinite precision. You will need to alter the design of your program to account for this fact. One common strategy is not to compare doubles using straight equality, but rather to say that two doubles are "equal" if the difference between them is less then some epsilon, i.e.
public const double epsilon = 0.000001; public bool DoubleEquals(double first, double second) { return Math.Abs(firstsecond) < epsilon; }
If you use that definition of "equality" then 0.99999999999999989 is in fact equal to 1 and your program should work as expected.
Rice's answer will also help with strategies to reduce (but not eliminate) the floating point errors in your code; they should be used in addition to this answer.
 Edited by servy42 Friday, May 4, 2012 2:49 PM
 Marked as answer by Mike Dos Zhang Thursday, May 10, 2012 10:47 AM
Friday, May 4, 2012 2:48 PM
All replies

This is expected, due to numerical approximation errors, you need to do rounding.
you could use the math.ceiling or math.round to correct the result.
to proof my theroy open windows calculator and calculate the cube root of 5
1.7099759466766969893531088725439
now close it
and type 1.7099759466766969893531088725439 then calculate the cube for it
it will be
5.0000000000000000000000000000003
Regards,
Ahmed Ibrahim
SQL Server Setup Team
This posting is provided "AS IS" with no warranties, and confers no rights. Please remember to click "Mark as Answer" and "Vote as Helpful" on posts that help you.
This can be beneficial to other community members reading the thread.Friday, May 4, 2012 1:05 PM 
result.ToString("0.0")Friday, May 4, 2012 1:08 PM

hi Ahmed,
I do agree with you, how ever i can not take that chance, because i am trying to calculate distance between two lat/lons using the standard formula.
but, that formula is internally depend on sin(degree) * sin(degree) + cos(degree) * cos(degree) = 1 rule.
any how thanks for the attempt to answer my question.
Friday, May 4, 2012 1:54 PM 
Some comments which you can cheerfully ignore.
First, as far as I know Math calculations use IEEE arithmetic so are correct to 15 decimal places. You won't get any more accurate than that. For a particular formula you might get much less, depending on how you arrange the calculations. That's a topic in numerical analysis.
Secondly, if you have a formula that contains "sin(a)*sin(a) + cos(a)*cos(a)" then simply replace it with 1, since that is true for all values of a. I suspect that the formula you refer to has something like "sin(a)*sin(b) + cos(a)*cos(b)". In that case of course you can't replace with 1, but there might be a rearrangement (perhaps using tan or some other trig function) that is numerically better behaved. But you still won't get better than 15 d.p.
Thirdly, if the built in sin and cos are not accurate enough you could of course write your own functions e.g. as a series sum (which I suspect is what Math.Sin does).
Regards David R

The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
Objectoriented programming offers a sustainable way to write spaghetti code.  Paul Graham.
Every program eventually becomes rococo, and then rubble.  Alan Perlis
The only valid measurement of code quality: WTFs/minute. Proposed as answer by servy42 Friday, May 4, 2012 2:40 PM
 Marked as answer by Mike Dos Zhang Thursday, May 10, 2012 10:47 AM
Friday, May 4, 2012 2:31 PM 
@Scotty & Ahmed
The problem can't just be fixed by rounding the result. Clearly the entire design of the program is based around the fact that doubles have infinite precision, and they don't. The program itself will likely need to be more fundamentally altered. Also keep in mind that if you have enough computations you can actually be off by more than one unit of whatever digit you round to, so just rounding can make things much worse.
@Naveen
Doubles don't have infinite precision. You will need to alter the design of your program to account for this fact. One common strategy is not to compare doubles using straight equality, but rather to say that two doubles are "equal" if the difference between them is less then some epsilon, i.e.
public const double epsilon = 0.000001; public bool DoubleEquals(double first, double second) { return Math.Abs(firstsecond) < epsilon; }
If you use that definition of "equality" then 0.99999999999999989 is in fact equal to 1 and your program should work as expected.
Rice's answer will also help with strategies to reduce (but not eliminate) the floating point errors in your code; they should be used in addition to this answer.
 Edited by servy42 Friday, May 4, 2012 2:49 PM
 Marked as answer by Mike Dos Zhang Thursday, May 10, 2012 10:47 AM
Friday, May 4, 2012 2:48 PM