在没有Math.sin函数的情况下在Java中实现Sine

时间:2017-07-26 17:24:30

标签: java sine

我正在尝试在不使用Math.sin(x)的情况下在Java中实现sine函数。所以我试图通过泰勒系列来实现这一点。不幸的是,这段代码给出了错误的结果。

如果您不知道泰勒系列是什么,请看一下:

以下是我创建的代码段:

public static double sin(double a) {
   double temp = 1;
   int denominator = -1;
   if(a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) {
      return Double.NaN;
   } 
   if(a != 0) {
      for (int i = 0; i <= a; i++) {
         denominator += 2;
         if(i % 2 == 0) {
            temp = temp + (Math.pow(a, denominator) / Factorial.factorial(denominator));
         } else {
            temp = temp - (Math.pow(a, denominator) / Factorial.factorial(denominator));
         }
      }
   }
   return temp;
}

我找不到我做的错误。你呢?

2 个答案:

答案 0 :(得分:1)

您的问题是您正在使用要为正弦函数计算的值作为分母的限制。泰勒级数被评估为函数接近无穷大的极限。在这种情况下,您只是根据输入值的大小来评估它,这实际上没有意义。你应该将你的for循环比较替换为i < x,其中x是一个常数,表示你想做的精确(对于低至20左右的值,该函数相当准确)。

答案 1 :(得分:0)

您的代码中存在两个主要问题。第一个问题是您将i0循环到a。这意味着,如果a为负值,则for循环甚至不会启动,您的结果将始终为1.0。然而,如果a为正,则循环开始,但它在(int) a次迭代后停止,并且它没有多大意义,因为当迭代n趋于无穷大时,泰勒拟合工作正常。 / p>

第二个主要问题是您没有对输入值a进行足够的控制。 正如我在Python: Calculate sine/cosine with a precision of up to 1 million digits

中所说的那样
  

x 0 为中心的真实泰勒展开是:

     

enter image description here

     

其中 Rn 拉格朗日剩余

     

enter image description here

     

请注意,只要 x 离开中心, Rn 就会快速增长    X0

     

由于您正在实施 Maclaurin系列(泰勒系列   以0)为中心而不是一般的泰勒系列,你的功能   在尝试计算 sin(x)时会给出非常错误的结果    x 的重要值。

所以在for循环之前,你必须将域名减少到至少 [ - pi,pi] ...如果你把它减少到 [0,pi]会更好并利用正弦的奇偶校验。

工作代码:

public static double sin(double a) {

    if (a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) {
        return Double.NaN;
    }

    // If you can't use Math.PI neither,
    // you'll have to create your own PI
    final double PI = 3.14159265358979323846;

    // Fix the domain for a...

    // Sine is a periodic function with period = 2*PI
    a %= 2 * PI;
    // Any negative angle can be brought back
    // to it's equivalent positive angle
    if (a < 0) {
        a = 2 * PI - a;
    }
    // Also sine is an odd function...
    // let's take advantage of it.
    int sign = 1;
    if (a > PI) {
        a -= PI;
        sign = -1;
    }
    // Now a is in range [0, pi].


    // Calculate sin(a)

    // Set precision to fit your needs.
    // Note that 171! > Double.MAX_VALUE, so
    // don't set PRECISION to anything greater
    // than 84 unless you are sure your
    // Factorial.factorial() can handle it
    final int PRECISION = 50;
    double temp = 0;
    for (int i = 0; i <= PRECISION; i++) {
        temp += Math.pow(-1, i) * (Math.pow(a, 2 * i + 1) / Factorial.factorial(2 * i + 1));
    }

    return sign * temp;

}