- ベストアンサー
Fortranでベッセル関数のべき級数展開が正しく計算できない!!!
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
「これでいけば簡単」という方針は #3 に書いておいたんだけどなぁ.... よく読めば「プログラムを要求している」だけじゃないと気付く, はず.
その他の回答 (7)
- Tacosan
- ベストアンサー率23% (3656/15482)
ん~, 少なくとも Horner の方法では桁落ちしますね. まあ, 交項級数なのでその可能性は想定できたわけですが.... 他の方法でも, 部分和の大きさに対して最終的な結果は非常に小さいので, やっぱり落ちてると思います. ベッセル関数を計算するルーチンには公開されているものもありますが, 大きな z に対しては漸近展開に切り替えてますね. Numerical Recipes だと |z| > 8 で切り替えてます.
- spring135
- ベストアンサー率44% (1487/3332)
NO.5です。もっと丁寧に書きます。 Sn=Π(k=1→n)(z/2k)^2 J0=Σ(n=1→∞)(-1)^n*Sn とします。
補足
回答有難うございます。 さっそく試してみましたが、zが38ぐらいまで計算できるようになりました。 目から鱗の方法でした。 しかし、まだまだ大きなzについて出来るようになりたいと考えております。 これはもう諦めた方が賢明ですかね? 漸近展開については比較はしておりません。 また試してみたいと思います。
- spring135
- ベストアンサー率44% (1487/3332)
>(1)1/N!の計算結果の呼び出し(別のループで計算済み) >(2)(A/2)^2Nの計算 これではだめです。 (A/2)^2N/N!(N=1,2,...) を計算して足し合わせるようにしてください。大きな数と小さな数を作らないようにするのがコツです。 漸近式の計算結果と比較してみましたか
#2です。 桁落ちが原因であるかどうかをみるために、各Nでの項の値を調べることをお勧めします。
- Tacosan
- ベストアンサー率23% (3656/15482)
まず「正しく計算できない」とだけ述べるのではなく, 「期待する結果」と「実際に得られた結果」を書くようにしてください. 例えば「z の値がこれこれのときに本当はこうならなきゃいけないんだけど得られた結果はこうである」と書いてください. また, 数値計算を行うにあたっては「どのようなプログラムで計算したのか」は重要な情報となります. ですので, できる限りあなたが用いたプログラムを出すようにしてください. ということで本題だけど, 交項級数なので #2 でも言われるようにどうしても精度は悪くなりがちです. できれば努力と根性で交項級数じゃないようにした方がいい. あるいは, n の上限を 100 にしているのだから単なる多項式とみなせるので, Horner の方法なんかを使ってもいいかもしれない.
補足
ご指摘有難うございます。 プログラムですが、簡単に書きますと、 ******************************* DO 1 Z=1,40,1 (ベッセル級数のzの値) SUM=0 DO 2 N=0,NN,1 (無限級数の重ね合わせ NN:無限級数の上限(100)) (1)1/N!の計算結果の呼び出し(別のループで計算済み) (2)(A/2)^2Nの計算 (3)(-1)^Nの計算 DSUM=(1)*(2)*(3) SUM=SUM+DSUM 2 CONTINUE 結果出力(Z=○のときにJ0(A)は▲) 1 CONTINUE ******************************** そして、結果ですが、 A__J0(A)の真値__級数による解 1__0.76519____0.76519 ・ 32__0.13807____0.1380465 40__7.37E-03___-0.398868 42__-1.15E-01___3.65E+00 44__8.63E-02___ -25.0222 46__3.94E-02___ 294.5768 ・ 50__5.58E-02___ -1.03E+04 ・ 60__-9.15E-02___2.40E+08 のようになります。 1~31程度 ほぼ一致 32~40程度 僅かにずれ それ以降 爆発的に誤差が大きくなる これで再度検討していただけたらありがたいです。
よくわかりませんが、ひょっとして桁落ちしていませんか? 正の項と負の項があるので、気になります。 また、収束性が悪くなっているということはありませんか?
補足
回答ありがとうございます。 桁落ちはしていることはしてるのですが、それが原因なのかもわからない状況です。
- Mr_Holland
- ベストアンサー率56% (890/1576)
>どうも、(z/2)^2nの項が大きくなりすぎることが原因です。 数値が大きくなりすぎることに対処するには、Σの中身の対数をとるなどして、数値を小さくして計算すると良いと思います。 L(n)=log|(-1)^n/n!^2 (z/2)^(2n)} とします。(logは常用対数とします。) すると、L(n)は次のように表されます。 L(n)= log{(z/2)^(2n)/n!^2} =2n log(z/2)-2 log(n!) これで計算すれば、数値が扱える範囲を超えることは防げると思います。 あとは、J_0(n)はつぎのように足し併せて計算できます。 J_0(n) =Σ[n=0→∞] (-1)^n 10^L(n)
補足
直ちに回答して頂き有難うございます。 さて、対数の件ですが、既に試したのですがやはりzが同じぐらいの値のときに 計算結果がおかしくなってしまいました。 底を大きくしたりも試したのですが、うまくいきません。 他に考えられることってなんかありますか? 現在は(z/2)^2nをどうにか簡単にできないかと考えてます。 (1/n!)^2を(1/n!)(1/n!)と分離して(z/2)^n(z/2)^nと分離したものと 打ち消しても同様の結果でした。orz...
お礼
honerをためしましたが、結局桁落ちしているみたいです。
補足
コメント足らずで申し訳ございません。 Horner の方法などはいろいろ不都合がありまして元々考えてはいませんでした。 べき級数展開をするしかない状況で計算が出来ないので非常に困っております。