The accuracy of Math.Sin () and Math.Cos () in C #

I am terribly annoyed by the inaccuracy of the built-in trigger functions in the CLR. It is well known that

Math.Sin(Math.PI)=0.00000000000000012246063538223773 

instead of 0. Something similar happens to Math.Cos(Math.PI/2) .

But when I do a long series of calculations, which in special cases evaluate to

 Math.Sin(Math.PI/2+x)-Math.Cos(x) 

and the result is zero at x = 0.2, but not zero at x = 0.1 (try). Another problem is that the argument is a large number, the error becomes proportionally large.

So, interestingly, someone encoded a better idea of ​​trigger functions in C # for sharing with the world. Does the CLR invoke the standard C math library that implements CORDIC or something similar? link: wikipedia CORDIC

+7
c # clr cosine
Jul 14 '10 at 7:25
source share
5 answers

You need to use the decimal library with arbitrary precision. (.Net 4.0 has an arbitrary integer class , but not a decimal).

Several popular ones are available:

+2
Jul 14 '10 at 23:21
source share

This has nothing to do with the accuracy of trigonometric functions, but more with a system like CLS. According to the documentation, double has an accuracy of 15-16 digits (this is exactly what you get), so you cannot be more accurate with this type, therefore, if you need higher precision, you will need to create a new type capable of it keep.

Also note that you should never write code like this:

 double d = CalcFromSomewhere(); if (d == 0) { DoSomething(); } 

Instead, you should:

 double d = CalcFromSomewhere(); double epsilon = 1e-5; // define the precision you are working with if (Math.Abs(d) < epsilon) { DoSomething(); } 
+18
Jul 14 '10 at 19:35
source share

I hear you. I am terribly annoyed by the inaccuracy of division. The other day I did:

 Console.WriteLine(1.0 / 3.0); 

and I got 0.33333333333333333, instead of the correct answer, which is 0, 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 ...

Perhaps now you see what the problem is. Math.Pi is not equal to pi not more than 1.0 / 3.0, equal to one third. Both of them differ from the true value by several hundred quadrillion, and therefore any calculations that you perform with Math.Pi or 1.0 / 3.0 will also be disabled by several hundred quadrillion, including the reception of the sine.

If you do not like that approximate arithmetic is approximate, then do not use approximate arithmetic. Use exact arithmetic. I used to use Waterloo Maple when I needed exact arithmetic; perhaps you should buy a copy of this.

+9
Jul 14 2018-10-14T00:
source share

This is the result of floating point precision. You get a certain number of significant digits, and everything that cannot be accurately represented is approximated. For example, pi is not a rational number, and therefore it is impossible to obtain an accurate representation. Since you cannot get the exact value of pi, you won’t get the exact sines and cosines of numbers, including pi (and you won’t get the exact value of sines and cosines most of the time).

Best Intermediate Explanation "What Every Computer Scientist Should Know About Floating-Point Arithmetic . " If you do not want to delve into this, just remember that floating point numbers are usually approximations, and floating point calculations are like moving a pile of sand on the ground: with everything you do with them, you lose a little sand and pick up some dirt.

If you want an accurate representation, you need to find a system of symbolic algebra.

+6
Jul 14 '10 at 19:53
source share

I reject the idea of ​​rounding errors. What can be done is to define sin(x) as follows, using a 6-member Taylor expansion:

  const double π=Math.PI; const double π2=Math.PI/2; const double π4=Math.PI/4; public static double Sin(double x) { if (x==0) { return 0; } if (x<0) { return -Sin(-x); } if (x>π) { return -Sin(x-π); } if (x>π4) { return Cos(π2-x); } double x2=x*x; return x*(x2/6*(x2/20*(x2/42*(x2/72*(x2/110*(x2/156-1)+1)-1)+1)-1)+1); } public static double Cos(double x) { if (x==0) { return 1; } if (x<0) { return Cos(-x); } if (x>π) { return -Cos(x-π); } if (x>π4) { return Sin(π2-x); } double x2=x*x; return x2/2*(x2/12*(x2/30*(x2/56*(x2/90*(x2/132-1)+1)-1)+1)-1)+1; } 

The typical error is 1e-16 , and the worst is 1e-11 . This is worse than the CLR, but it can be controlled by adding more terms. The good news is that for special cases in OP and for Sin(45°) answer is accurate.

+1
Jun 27 2018-12-12T00:
source share



All Articles