2017-07-26 27 views
0

Math.sin(x)を使わずにJavaで正弦関数を実装しようとしています。だから私はテイラーシリーズでこれを実現しようとしている。残念ながら、このコードは間違った結果を返します。Math.sin関数なしの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; 
} 

私はできない顔をしている

あなたはテイラー級数が何であるかわからない場合は、私がした間違いを見つけてください。あなたは?

+1

何の結果、あなたが期待してなかった、とあなたは何を得るのですか?これまでに何をデバッグしましたか? –

+1

なぜ用語の数は 'a'の値に依存しますか?それはあなたが提供したテイラー展開とは一貫していません。 – bradimus

+1

問題は 'i <= a'にあります。 – talex

答えて

0

コードには2つの主な問題があります。最初の問題は、i0からaにループしていることです。つまり、aが負の値の場合、forループは開始されず、結果は常に1.0になります。一方、aが正の場合、ループが開始しますが、(int) aの反復後に停止します。反復nが無限になると、Taylorの近似がうまく動作するため、あまり意味がありません。

第2の大きな問題は、入力値aで十分なコントロールを行っていないことです。 IはすでにXの中心に実際のテイラー展開はPython: Calculate sine/cosine with a precision of up to 1 million digits

に述べたように:

Rnの

ラグランジュ剰余である

enter image description here

enter image description hereRnのX離れる中央 X0から速いとすぐに成長することを

注意。

あなたは一般的なテイラー級数マクローリンシリーズ(0を中心にテイラー級数 )を実装していませんので ため罪(x)のを計算しようとしたとき、あなたの関数 は本当に間違った結果が得られますxの大きな値。あなたは[0、PI]にそれを削減し、サインのパリティを利用する場合

だからforループの前に、あなたはより良い...少なくとも[-pi、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; 

} 
1

問題は、サイン関数の評価対象となる値を分母の限界値として使用していることです。テイラー級数は、関数の限界が無限に近づくにつれて評価されます。この場合、実際には意味をなさない入力値のサイズに対してのみ評価しています。 forのループ比較をi < xに置き換えてください。ここで、xは正確に表す定数です(この関数は20程度の低い値に対してかなり正確です)。

+1

実際に、あるポイントで 'x'を増やすと、数値の有限表現がますます不正確になるため、精度が低下し始めます。 – talex

関連する問題