• ベストアンサー

Fortranでベッセル関数のべき級数展開が正しく計算できない!!!

Fortranでベッセル関数のべき級数展開が正しく計算できない!!! タイトルの通りです。ベッセル関数のべき級数展開は画像に添付した通りです。 この計算をFortranで行っているのですが、式中のzが30以上になると、正しく 計算できません。zが30以下のときは、ベッセル関数の値と完全に一致しています。 どうも、(z/2)^2nの項が大きくなりすぎることが原因です。 これの解決法をどなたかご存知ですか? もしご存知でしたらご教授願います。 ちなみに∞はn=100までで計算をしています。 ほんと死にそうです。。。助けて下さい。

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.7

「これでいけば簡単」という方針は #3 に書いておいたんだけどなぁ.... よく読めば「プログラムを要求している」だけじゃないと気付く, はず.

dothesex
質問者

お礼

honerをためしましたが、結局桁落ちしているみたいです。

dothesex
質問者

補足

コメント足らずで申し訳ございません。 Horner の方法などはいろいろ不都合がありまして元々考えてはいませんでした。 べき級数展開をするしかない状況で計算が出来ないので非常に困っております。

その他の回答 (7)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

ん~, 少なくとも Horner の方法では桁落ちしますね. まあ, 交項級数なのでその可能性は想定できたわけですが.... 他の方法でも, 部分和の大きさに対して最終的な結果は非常に小さいので, やっぱり落ちてると思います. ベッセル関数を計算するルーチンには公開されているものもありますが, 大きな z に対しては漸近展開に切り替えてますね. Numerical Recipes だと |z| > 8 で切り替えてます.

  • spring135
  • ベストアンサー率44% (1487/3332)
回答No.6

NO.5です。もっと丁寧に書きます。 Sn=Π(k=1→n)(z/2k)^2 J0=Σ(n=1→∞)(-1)^n*Sn とします。

dothesex
質問者

補足

回答有難うございます。 さっそく試してみましたが、zが38ぐらいまで計算できるようになりました。 目から鱗の方法でした。 しかし、まだまだ大きなzについて出来るようになりたいと考えております。 これはもう諦めた方が賢明ですかね? 漸近展開については比較はしておりません。 また試してみたいと思います。

  • spring135
  • ベストアンサー率44% (1487/3332)
回答No.5

>(1)1/N!の計算結果の呼び出し(別のループで計算済み) >(2)(A/2)^2Nの計算 これではだめです。 (A/2)^2N/N!(N=1,2,...) を計算して足し合わせるようにしてください。大きな数と小さな数を作らないようにするのがコツです。 漸近式の計算結果と比較してみましたか

noname#185706
noname#185706
回答No.4

#2です。 桁落ちが原因であるかどうかをみるために、各Nでの項の値を調べることをお勧めします。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

まず「正しく計算できない」とだけ述べるのではなく, 「期待する結果」と「実際に得られた結果」を書くようにしてください. 例えば「z の値がこれこれのときに本当はこうならなきゃいけないんだけど得られた結果はこうである」と書いてください. また, 数値計算を行うにあたっては「どのようなプログラムで計算したのか」は重要な情報となります. ですので, できる限りあなたが用いたプログラムを出すようにしてください. ということで本題だけど, 交項級数なので #2 でも言われるようにどうしても精度は悪くなりがちです. できれば努力と根性で交項級数じゃないようにした方がいい. あるいは, n の上限を 100 にしているのだから単なる多項式とみなせるので, Horner の方法なんかを使ってもいいかもしれない.

dothesex
質問者

補足

ご指摘有難うございます。 プログラムですが、簡単に書きますと、 ******************************* 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程度 僅かにずれ それ以降  爆発的に誤差が大きくなる これで再度検討していただけたらありがたいです。

noname#185706
noname#185706
回答No.2

よくわかりませんが、ひょっとして桁落ちしていませんか? 正の項と負の項があるので、気になります。 また、収束性が悪くなっているということはありませんか?

dothesex
質問者

補足

回答ありがとうございます。 桁落ちはしていることはしてるのですが、それが原因なのかもわからない状況です。

  • Mr_Holland
  • ベストアンサー率56% (890/1576)
回答No.1

>どうも、(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)

dothesex
質問者

補足

直ちに回答して頂き有難うございます。 さて、対数の件ですが、既に試したのですがやはりzが同じぐらいの値のときに 計算結果がおかしくなってしまいました。 底を大きくしたりも試したのですが、うまくいきません。 他に考えられることってなんかありますか? 現在は(z/2)^2nをどうにか簡単にできないかと考えてます。 (1/n!)^2を(1/n!)(1/n!)と分離して(z/2)^n(z/2)^nと分離したものと 打ち消しても同様の結果でした。orz...

関連するQ&A