예제 #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 shortcommings 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 user
 /// that the result should not be trusted. No floating point standard specifies this crazy behavior.)
 /// Another shortcomming, 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 shortcommings 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
 /// number is very large, 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-negligable faction of 2&#x3C0;, there is a non-neglible fraction
 /// of the values between -1 and +1 in the corresponding range of function values; any of these values is as good as any other as an answer to the
 /// question of the sine of our uncertain argument, so we should be satisfied with any returned value in this non-negligible range.
 /// </para>
 /// <para>A contrary view is that it is better to treat all arguments as infinitely precise and return the nearest representable <see cref="System.Double"/>
 /// to the actual function value under this assumption. Users are unlikely to complain that we returned a more accurate value and this behavior is particularly
 /// useful when the argument is an intermediate result that the programmer may not even realize has become large.</para>
 /// <para>For typical arguments, say between 10<sup>-4</sup> and 10<sup>4</sup>, the extra cost of this function over
 /// <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, higher-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 is beyond the range of the built-in function eintirely, use our range-reduction algorithm
         return(RangeReduction.Sin(x));
     }
 }
예제 #2
0
        internal static double SinPi(double x)
        {
            long   y0;
            double y1;

            RangeReduction.ReduceByOnes(2.0 * x, out y0, out y1);
            return(RangeReduction.Sin(y0, y1));
        }
예제 #3
0
 /// <summary>
 /// Computes the sine of the given multiple of &#x3C0;.
 /// </summary>
 /// <param name="x">The argument.</param>
 /// <returns>The value of sin(<paramref name="x"/>&#x3C0;).</returns>
 /// <remarks>
 /// <para>This function allows the user to increase performance and avoid inaccuracies due to the finite
 /// precision of the stored constant <see cref="Math.PI"/> in some cases. Suppose you need to compute
 /// sin(x&#x3C0;) for a large value of x.
 /// </para>
 /// </remarks>
 /// <seealso cref="CosPi(double)"/>
 public static double SinPi(double x)
 {
     RangeReduction.ReduceByOnes(2.0 * x, out long y0, out double y1);
     return(RangeReduction.Sin(y0, y1));
 }