• ベストアンサー

C++プログラムでのおかしな挙動

初めまして。 自力で解決しようと試みましたが、どうしても無理なのでここでお聞きしようと思い、質問させて貰います。 Visual C++の環境にてモンテカルロシミュレーションでの同期加算処理のプログラムを書いた所、1.#INF00と値が返ってくる場合があります。 配列がとても大きくなる(tmp[1000][360]など)ので、new関数にてメモリ領域を確保しています。 同期加算計算を300回以上行った時に1.#INF00という値がちらほらと返ってくるのです。 これは処理の量と関係あるように思えますが、解決する方法はあるのでしょうか。 ちなみに for( i=0; i<n; i++ ){ for( j=0; j<TIME; j++ ){ out[i] = out[i] + tmp[j][i]; } out[i] = out[i] / TIME; } ※TIME = 1000、n = 360 という計算です。 質問内容がわかりにくくてすいませんが、急ぎなのでよろしくお願い致します。

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

  • ベストアンサー
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.4

yahoo!ブリーフケースを拝見しました。 既にNo3の方の回答で解決済みと思われますが、 RAND関数を以下のように修正して下さい。 long double RAND() { long double x; do { x = rand(); x = x/RAND_MAX; } while (x == 0.0); return (x); } これで、エラーがとれると思います。

gardens
質問者

お礼

質問同時からお付き合い頂き、誠に有り難うございます。 なんとか助力にて解決に至りました。 このようなエラーの回避方法を学ばなくては…と心底思いました。 親身に相談に乗って頂き、重ね重ねお礼申し上げます。 有り難うございました。

その他の回答 (3)

  • isobeman
  • ベストアンサー率41% (17/41)
回答No.3

他の方も同じように説明していますが、「1.#INF00」 はデータ型の値の範囲を超えた場合に起こります。 結果として「1.#INF00」が出現すると言うことは、途中の課程で値の範囲を超えたことを示します。 まず、やることとしては、どの瞬間にエラーとなっているのかデバッガで結果を基に追いかけることだと思います。 何番目の結果がエラーなのか?(エラーの場所は固定されていますよね?) そのエラーを作成しているforループを逐一デバッガで止めて値の確認をする必要があると思います。 そうしてさかのぼると、BOXMULLER()関数内でエラーが生成されることがわかると思います。 確認のためのコードは以下です。 long double BOXMULLER() { long double mu = 0; /* 平均μ=0 */ long double sigma = 0.01; /* 分散σ=0.01 */ long double rnd = RAND(); long double loged = log(rnd); long double sqrted = sqrt(-2*sigma*sigma*loged); return (sqrted*sin(2*PI*RAND())+mu); } Yahoo!ブリーフケースのソースを元に式を変形しています。 この log(rnd) にてエラーが発生しています。 理由は、rnd=0 の場合があるためです。 log(0)は、計算できません。 あなたの関数 RAND() は、 /* 0以上1未満の一様乱数を発生させる関数 */ となっていますが、0を許可しているため、log(0) になる可能性があります。 あと、 srand( (unsigned)time( NULL ) ); で、疑似乱数の初期化をしないと、毎回同じ結果になりますよ。 (同じ場所でエラーになった方がデバッグはしやすいですけどね。) ---- 個人的には、Yahoo!ブリーフケースなどの他のシステムを使用して説明を行うことに異議があります。このシステム上にすべての情報が残らないため、後から見た人が質問を理解できない可能性があるためです。 できる限り、質問スペースや、補足スペースに納めた方がよいと思います。

gardens
質問者

お礼

分かりやすい説明、有り難うございました。 皆様方の助力により無事解決に至りました。 重ね重ねお礼申し上げます。 また、Yahoo!ブリーフケースを使ったのはこの場所に書くと長くなり過ぎると思ったからです。 しかし、後々の人の事を考えるとご指摘の通り掲載した方が良かったかな、と思いました。 これからは気を付けたいと思います。 有り難うございました。

  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

double型ではおよそ10の308乗(1e308)が、表現出来る数の最大値となっています。今回この値を超えた為に、1.#INF00が発生します。 従って対策としては、 1案.この値を超えないようなアルゴリズムに変換すること。 2案.long double型を使用すること。 が考えられます。但し、long double型でも、上限はありますので、これを越える場合は1案になるかと思います。 念の為確認しますが、Newで確保した、tmp[1000][360]の領域は、0で初期化を行ってますでしょうか。

gardens
質問者

お礼

yahoo!ブリーフケースに問題のプログラムをUPしました。 もし宜しければ一読願えませんでしょうか? ID : program_help2004 Pass : zxcvb です。 厚かましいですが、本当に困っている為、宜しくお願いします。

gardens
質問者

補足

お返事有り難うございます。 long double型にする方法を試してみようと思います。 あと、tmp[1000][360] = 0.0としていますが、 0の方がいいのでしょうか。 2案→1案で頑張ってみます♪

回答No.1

こんなロジックの一部だけじゃ、理解できんだろ? 1.out[i]には元々何が入ってる? 2.どうやってnewしてる?因みにnewですべての領域持つんだから、tmp[1000][360]で持っても同じだろ? 3.「1.#INF00」は、どうやって見た?デバッガで値を見たのか、それとも出力ロジックで画面か、ファイルに出したのか?またそのロジック。 せめてこのくらいは情報が無いと、これだけのロジックじゃ、何にも解らんじゃん。

gardens
質問者

補足

わかりにくくて申し訳ありません。 out[i]はdouble型の同期加算結果を入れる為の物で、 初期化の為にout配列全てに0.0を入れてあります。 newの事はよく分からないまま使いました。 最初にtmp[1000][360]と宣言すると動作しなかったからです。 1.#INF00はファイルに出力して見ました。 for( i=0; i<360; i++ ){ fprintf(fp, "%lf\n",out[i]); } にて出力し、同期加算結果の正弦波をエクセルにて表示させようとしていました。 まだまだわかりにくくてすいません。

関連するQ&A

専門家に質問してみよう