2016-06-23 8 views
3

私はJavaで正弦関数を近似するために書いた方法で少し腹立たしいです。ここは、テイラーのシリーズに基づいています。少し値についてJavaの正弦近似エラー

static double PI = 3.14159265358979323846; 
    static double eps = 0.0000000000000000001; 

    static void sin(double x) { 
    x = x % (2 * PI); 
    double term = 1.0; 
    double res = 0.0; 

    for (int i = 1; term > eps; i++) { 
     term = term * (x/i); 
     if (i % 4 == 1) res += term; 
     if (i % 4 == 3) res -= term; 
    } 
    System.out.println(sum); 
} 

、私はサインの非常に良い近似を得たが、大きな値(例えばPOW(10,22))のために、結果は非常に非常に間違っているようです。ここで

結果は以下のとおりです。

sin(pow(10,22)) // 0.8740280612007599 
Math.sin(pow(10,22)) // -0.8522008497671888 

誰かがアイデアを持っていますか?ありがとうございました !

敬具、

答えて

3

は、Java sin機能があまりにもオフになることを安心すること。

sinのテイラー展開で収束半径が小さく、その半径内に収まっていても収束が遅いという問題があります。

浮動小数点の考慮事項もあります。浮動小数点doubleは、約15の有効数字を提供します。任意の整数nため

sin(x + 2 * pi * n) = sin(x)

そこでsinための大引数ため、精度が特にsin周期関数であることを考えると著しく低下します。

+0

私はx = x%(2 * PI);と考えました。このような精度の低下は避けられます(パラメータの近似値であっても)。これを減らす方法はありますか? –

+0

最初の 'x'はすでにあまりにも近似しています。定期的な関数で大きな浮動小数点引数を使用することはできません。それは私が恐れる人生です。良い質問。私は誰もそれをupvotedしていない驚いている。 – Bathsheba

+0

ありがとうございました!別の方法を見てみましょう(友人と私は学校に新しい言語を書いています。私たちはMathクラスを実装する必要があります)。もし有用な参考文献があれば;) –

1

doubleのプレゼンテーションのために多くの丸め誤差が累積するため、大きな数値の答えは正しくありません。数字が大きい場合、ループは、termがイプシロンより小さくなる前に多くの繰り返しを行います。各反復では、丸め誤差が蓄積されます。結果は最終的な値に非常に大きな誤差があります。 「数値解析」の素敵なリファレンスを読んでください。とにかく、Tylorの系列は定義によって0に近いsinに近似しています。だから、非常に大きな数字には間違いないのが普通です。

0

実際には、テーラー級数の収束半径とはまったく関係がありません。このような大きな数値に必要な精度を保持するには、倍精度精度とは関係ありません。正弦関数のテイラー級数の半径は無限大です。

10^22は約2^73です。倍精度数の仮数は52ビットであるため、倍精度形式で格納できる連続した値は2^21になります。正弦関数の評価にはそれ以上の分解能が必要なため、信頼できる答えを得ることはできません。