- ベストアンサー
C言語で正の整数nを受け取って、フィボナッチ数列を求めるプログラム
- C言語で正の整数nを受け取り、フィボナッチ数列を求めて表示するプログラムがありますが、答えがおかしくなる問題があります。
- また、大きな値を指定するとプログラムが停止し、ファイルを保存する際に不具合が起こる問題もあります。
- これらの問題について、解決策を教えていただきたいです。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
> a[46] = 1836311903 > a[47] = -1323752223 となることでしたら、符号付きint(32bit)で表現できる範囲をオーバーフローした結果なので「正しい」です。 a[45] = 1134903170 = 0x43a53f82 a[46] = 1836311903 = 0x6d73e55f a[47] = 2971215073 = 0xb11924e1 ↑最上位が1なので、符号付きの場合、負の値(2の補数表現) → -1323752223 また、符号無し(unsinged int)でやっても、 a[48] = 4807526976 = 0x11e8d0a40 →32bitまで 0x1e8d0a40 = 512559680 とオーバーフローします。 64bit整数を使うともう少し長くなりますが、93までです。 根本対策は、必要なだけのビット幅を持った整数を使うことです。 Cでも多倍長精度整数のライブラリがありますし、自作もでますが、 数列をファイルに出力するだけなら、PythonやRubyといった、無限精度整数を持っている言語を使うのが簡単です。 >また、a[ ]の配列をもっと増やす方法はないでしょうか・・・ >大きな値を指定してやると、プログラムを実行したら「このプログラムは停止しました~」という画面が出てきます・・・ 9999 と指定しているので、9998までしか保証されません。 Cでは、配列の添字のチェックはしないので、それより大きな値を使ってもなにくわぬ顔で実行しようとします。 方法として ・nが決まってから、必要な大きさの領域をmalloc/callocを使って確保する(使用後の解放は忘れずに) ・今回ので言えば、直前2つの値だけわかればいいので、それだけを確保し、値は随時出力する。 >また、ファイルを保存するときにfprintfで保存しようと思うのですがa+だとうまく保存されるのですがw+だと最後から一つ前のものしか書き込まれません・・・なぜなのでしょうか・・ openしたときのファイルポインタの位置の違いでしょう。 w+はポインタが先頭なので、書き込むとそこから上書き a+はファイルの最後に移動するので、書き込めばその続きから。 それより、1回のfopenでまとめて書いた方が効率よくないですか? 上の「2つだけ確保」と合せて int a[2]; int A ; a[0]=0; a[1]=0; FILE *file; file = fopen("k04a.txt","w"); for (i=1;i<n;i++) { if( i == 1 || i == 2 ){ A=1; }else{ A=a[0]+a[1]; } a[0]=a[1]; a[1]=A; printf("a[%d] = %d\n",i,A); fprintf(file,"a[%d] = %d\n",i,A); } fclose(file);
その他の回答 (4)
- Kules
- ベストアンサー率47% (292/619)
A No.1のKulesです。 まあ他の回答者が書かれているのですでにその間違いには気付かれているとは思いますが… >そうかunsigned intなら整数ってことにできますねー^^ unsigned intにすることで、表現できる最大の整数の値がちょっと増える(大体倍になる)だけで、 本当に「焼け石に水」程度の効果しかありません。私も使ったことはありませんが、多倍長精度整数やら 無限精度整数やらといった、もっと大きな数値を扱えるような型を使うのがいいんでしょうね。 以上、参考までに。
お礼
わざわざありがとうございます! たしかintでマイナスであった分がプラスで持ってこれるようになるから倍になるんでしたよね! うろ覚えではありますが・・・・・・・ kmeeさんにも教えていただきましたが、多倍長精度整数やら無限精度整数等大きな数値を扱える型があるらしいですね! 自分も初めて聞きました・・・・・ この際なのでそれでもう一度やってみようかと思っています! 大変参考になりました! ありがとうございます!
- okormazd
- ベストアンサー率50% (1224/2412)
intなので,nはせいぜい46までしか正しい値を示しません。 fopenやfcloseをforの外に出したほうがいい。 いずれも前の回答者さんのとおりです。 >一つ前のものしか書き込まれません は, for (i=1;i<n;i++) { を, for (i=1;i<=n;i++) { にすればいいのではないですか。
お礼
あっ! なんとイコールを付けていなかったとは ありがとうございました!
- neko1963
- ベストアンサー率49% (127/258)
> a+だとうまく保存されるのですがw+だと最後から一つ前のものしか書き込まれません・・・ fopenのモードでは ・"a+" ・・・ 読み込み/追加書き出し ・"w+" ・・・ 読み込み/書き出し となっています。 "a+" ではファイルの最後に追加していきます。 "w+" ではファイルの内容が失われます。 そもそも、for ループの中で fopenを行っているのはなぜでしょうか? for (i=1;i<n;i++) { fprintf(file,"a[%d] = %d\n",i,a[i]); } にして、 FILE *file; file = fopen("k04a.txt","w+"); はプログラムの前の方に移動、 fclose(file); は return 0;の直前に移動すれば良いのではないでしょうか。
お礼
>>そもそも、for ループの中で fopenを行っているのはなぜでしょうか? 確かにその必要はなかったです! ありがとうございます! おかげさまでファイルの書き込みはうまくいくようになりました! まあ入力した項のひとつ前しかなぜか表示されませんが・・・ w+やa+の説明もわかりやすくありがとうございました!
- Kules
- ベストアンサー率47% (292/619)
私もCはほとんど素人ですが… フィボナッチ数列って結構な勢いで値増えていきますよね?第30項で83万ぐらいになってしまいます。 intってそんなに大きな数字は表せなかったような… というわけで1つの解決法としては、ほぼ焼け石に水ですが aをunsigned intで宣言する、あるいはlongとかlong longとかで宣言する というのがあると思います。 また、aを9999までしか用意していないのなら、nを10000より大きな数字を入れた時点でバッファオーバーラン?とかいうのが起きてだめになります。 さらに言うと、Cでの配列は要素0から定義されていたはずなので、少々気持悪いですが for(i=1;i<=n;i++){ ではなく for(i=0;i<n;i++){ とした方がいいように思います。 以上、参考になれば幸いです。
お礼
>>intってそんなに大きな数字は表せなかったような あっ・・・・・・・・そうでしたそういえば制限がありました・・・・・・ なるほど!ありがとうございました! >>さらに言うと、Cでの配列は要素0から定義されていたはずなので、少々気持悪いですが for(i=1;i<=n;i++){ ではなく for(i=0;i<n;i++){ とした方がいいように思います。 確かに0から指定してやることができるのはできるのですが、ここでは表示するときにa[1]から表示して見たかったので・・・・ ありがとうございました!助かりました! そうかunsigned intなら整数ってことにできますねー^^
補足
>>となることでしたら、符号付きint(32bit)で表現できる範囲をオーバーフローした結果なので「正しい」です。 なるほどー 確かにそうでした! ただunsigend charで指定しても47ですでに-1323752223だったり・・・・ >>根本対策は、必要なだけのビット幅を持った整数を使うことです。 おおお!多倍長精度整数のライブラリとかあるんですね! ありがとうございます! rudyやPythonは使ったことがなくて>< rudyはいつかやりたいんですけどね・・・・・ >>nが決まってから、必要な大きさの領域をmalloc/callocを使って確保する(使用後の解放は忘れずに) mallocやcalloc関数ですかー実は初耳で(汗 勉強してきます! >それより、1回のfopenでまとめて書いた方が効率よくないですか? 上の「2つだけ確保」と合せて おおおおおお なるほど! 確かにこういう風に書いたほうが効率いいですね! いろいろと勉強になりました! ありがとうございました!