Ejemplo n.º 1
0
 /// <summary>
 /// Computes the sine of the given value to full significance over the full range of arguments.
 /// </summary>
 /// <param name="x">The argument.</param>
 /// <returns>The value of sin(x).</returns>
 /// <remarks>
 /// <para>This method addresses several subtle shortcomings of the <see cref="System.Math.Sin" /> method.
 /// One shortcoming, quite striking but rarely encountered, is that <see cref="Math.Sin"/> returns entirely wrong results very large
 /// arguments -- for x larger than about 10<sup>20</sup>, it simply returns the argument as the function value!
 /// (I have no idea
 /// why the base class library designers did not at least choose to return <see cref="Double.NaN"/>, so as to signal to the caller
 /// that the result should not be trusted. No floating point standard specifies this crazy behavior.)
 /// Another shortcoming, more commonly encountered but often unnoticed, is that for large but not necessarily very large arguments,
 /// function values loose precision, particularly near zeros of the function.</para>
 /// <para>
 /// One way to view these shortcomings is that they are justified by the uncertainty inherent in floating point representations. In this
 /// view, any <see cref="System.Double"/> should be seen as an uncertain value with a relative error of ~10<sup>-16</sup>. If the
 /// argument is large enough, then the absolute size of this error can be as large or larger than 2&#x3C0;; in this circumstance we should not
 /// expect to be able to say anything about the value (except, of course, that it is between -1 and +1, which is violated by the designers' crazy
 /// choice to return the argument as the value). Even if the absolute error is just a non-negligible faction of 2&#x3C0;, there is a non-negligible fraction
 /// of the values between -1 and +1 in the corresponding range of function values; any of these values is as possible as any other as a value
 /// for the sine of our uncertain argument, so we should be satisfied with any returned value in this non-negligible range.
 /// </para>
 /// <para>A different view is that it is better to regard every representable floating point value as some exact rational number, and
 /// when computing functions of floating point numbers, we should strive to return the representable floating point value nearest
 /// to the actual function value for that exact rational.
 /// Callers are unlikely to complain if we are careful in this regard, and this behavior is particularly
 /// useful when the argument is an intermediate result that the programmer may not even realize has become large.
 /// Thus is the view that we adopt, and therefore we provide this improved trigonometric function.</para>
 /// <para>For typical arguments, say between -10<sup>4</sup> and 10<sup>4</sup>, the extra cost of calling this function instead of
 /// <see cref="Math.Sin"/> is just a couple of comparisons and a single floating point operation; less than 0.1% of
 /// arguments in this range are then routed to our much slower, high-accuracy algorithm. We therefore suggest that,
 /// for general use, you prefer this method over <see cref="Math.Sin"/>; only in very unusual situations where (i) you are guaranteed
 /// never to encounter very large arguments, (ii) full precision values are not required, and (iii) the run-time of your
 /// application is critical and dominated by trigonometric calculations, should you prefer the base class library method.</para>
 /// </remarks>
 public static double Sin(double x)
 {
     if (x < 0.0)
     {
         return(-Sin(-x));
     }
     else if (x < 1.0)
     {
         // If x is small enough not to cross a zero, use the built-in function
         return(Math.Sin(x));
     }
     else if (x < RangeReduction.xLimit)
     {
         // If x is in the intermediate region, try the built-in function but switch to our range-reduction
         // algorithm if the result is too small.
         double y  = Math.Sin(x);
         double ym = x / RangeReduction.xLimit;
         if (Math.Abs(y) < ym)
         {
             return(RangeReduction.Sin(x));
         }
         else
         {
             return(y);
         }
     }
     else if (x < Double.PositiveInfinity)
     {
         // If x is beyond the range of the built-in function entirely, use our range-reduction algorithm
         return(RangeReduction.Sin(x));
     }
     else
     {
         // If x is infinite or NaN, return NaN.
         return(Double.NaN);
     }
 }
Ejemplo n.º 2
0
 /// <summary>
 /// Computes the cosine of the given multiple of &#x3C0;.
 /// </summary>
 /// <param name="x">The argument.</param>
 /// <returns>The value of cos(<paramref name="x"/>&#x3C0;).</returns>
 /// <remarks>
 /// <para>For an explanation of why and when to use this function,
 /// see <see cref="SinPi(double)"/>.</para>
 /// </remarks>
 /// <seealso cref="SinPi(double)"/>
 public static double CosPi(double x)
 {
     RangeReduction.ReduceByOnes(2.0 * x, out long y0, out double y1);
     return(RangeReduction.Cos(y0, y1));
 }