C言語で正の整数n を受け取って、この数列の第1 項から第n 項までのフィボナッチ数列を求めて表示、および結果をファイルに保存するプログラムを作ってみました。
ですが、答えがおかしくなります(具体的にはーがつくものが交互にでてきます)・・・コンパイルはできたのですが・・・
環境はvisual c++2010expressです。
また、a[ ]の配列をもっと増やす方法はないでしょうか・・・大きな値を指定してやると、プログラムを実行したら「このプログラムは停止しました~」という画面が出てきます・・・
また、ファイルを保存するときにfprintfで保存しようと思うのですがa+だとうまく保存されるのですがw+だと最後から一つ前のものしか書き込まれません・・・なぜなのでしょうか・・
どなたか教えていただけないでしょうかm( )m
ソースはこちらです
#include<stdio.h>
int main(void){
int i;
int n;
int a[9999];
printf("n? ");
scanf("%d",&n);
while(n<0){
printf("nは0より大きい整数でお願いします\n");
printf("n? ");
scanf("%d",&n);
}
for(i=1;i<=n;i++){
if( i == 1 || i == 2 ){
a[i]=1;
}
else{
a[i]=a[i-1]+a[i-2];
}
}
for(i=1;i<=n;i++){
printf("a[%d] = %d\n",i,a[i]);
}
for (i=1;i<n;i++) {
FILE *file;
file = fopen("k04a.txt","w+");
fprintf(file,"a[%d] = %d\n",i,a[i]);
fclose(file);
}
return 0;
}
No.3ベストアンサー
- 回答日時:
> 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);
この回答への補足
>>となることでしたら、符号付きint(32bit)で表現できる範囲をオーバーフローした結果なので「正しい」です。
なるほどー
確かにそうでした!
ただunsigend charで指定しても47ですでに-1323752223だったり・・・・
>>根本対策は、必要なだけのビット幅を持った整数を使うことです。
おおお!多倍長精度整数のライブラリとかあるんですね!
ありがとうございます!
rudyやPythonは使ったことがなくて><
rudyはいつかやりたいんですけどね・・・・・
>>nが決まってから、必要な大きさの領域をmalloc/callocを使って確保する(使用後の解放は忘れずに)
mallocやcalloc関数ですかー実は初耳で(汗
勉強してきます!
>それより、1回のfopenでまとめて書いた方が効率よくないですか?
上の「2つだけ確保」と合せて
おおおおおお
なるほど!
確かにこういう風に書いたほうが効率いいですね!
いろいろと勉強になりました!
ありがとうございました!
No.5
- 回答日時:
A No.1のKulesです。
まあ他の回答者が書かれているのですでにその間違いには気付かれているとは思いますが…
>そうかunsigned intなら整数ってことにできますねー^^
unsigned intにすることで、表現できる最大の整数の値がちょっと増える(大体倍になる)だけで、
本当に「焼け石に水」程度の効果しかありません。私も使ったことはありませんが、多倍長精度整数やら
無限精度整数やらといった、もっと大きな数値を扱えるような型を使うのがいいんでしょうね。
以上、参考までに。
わざわざありがとうございます!
たしかintでマイナスであった分がプラスで持ってこれるようになるから倍になるんでしたよね!
うろ覚えではありますが・・・・・・・
kmeeさんにも教えていただきましたが、多倍長精度整数やら無限精度整数等大きな数値を扱える型があるらしいですね!
自分も初めて聞きました・・・・・
この際なのでそれでもう一度やってみようかと思っています!
大変参考になりました!
ありがとうございます!
No.4
- 回答日時:
intなので,nはせいぜい46までしか正しい値を示しません。
fopenやfcloseをforの外に出したほうがいい。
いずれも前の回答者さんのとおりです。
>一つ前のものしか書き込まれません
は,
for (i=1;i<n;i++) {
を,
for (i=1;i<=n;i++) {
にすればいいのではないですか。
No.2
- 回答日時:
> 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+の説明もわかりやすくありがとうございました!
No.1
- 回答日時:
私も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なら整数ってことにできますねー^^
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# 至急教えてください!プログラミングの問題です。 割られる整数と割る整数を受け取って、商と余りを出力す 3 2022/07/05 10:23
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# 至急教えてください! プログラミングの問題です! お願いします! 出力2と全く同じ出力をするように、 2 2022/06/22 23:10
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBAコードを張り付け後のエクセ...
-
C言語で正の整数n を受け取って...
-
drtファイルはどうしたら開...
-
巨大なテキストの最終行を取得...
-
fgets で値が取得できない
-
Firefox で file:// で始まる U...
-
csvファイルの横方向への改行に...
-
PerlでのUseless use...
-
window.open でのファイル指定方法
-
バッチファイルの作り方(CSV→...
-
空白文字 \\f と\\v の違いに...
-
batファイルでrenameができませ...
-
htaccessで特定のディレクトリ...
-
perlをwindows環境でshift-jis...
-
ディレクトリ名を取得したい
-
ReadLineでの読み出し行を指定する
-
sprintfについて
-
VBでファイル分割の方法
-
LinuxのC言語で、ファイル名の...
-
FindFirstFileとFindNextFileで...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
window.open でのファイル指定方法
-
python renameについて
-
巨大なテキストの最終行を取得...
-
fgets で値が取得できない
-
Firefox で file:// で始まる U...
-
【C++/CLI】ファイルオープンに...
-
PerlでのUseless use...
-
drtファイルはどうしたら開...
-
csvファイルの横方向への改行に...
-
VBA テキストファイルを読み取...
-
MATLABのm-fileについて
-
ファイル全てを .xlsm に変更し...
-
WindowsでPerlをする際,1行目の...
-
並び方、
-
VBAコードを張り付け後のエクセ...
-
fopen64について
-
JSP URLに表示される拡張子 .jsp
-
重複ファイル名ある場合ファイ...
-
行を指定して削除する方法PERL
-
複数ファイルを1つにするシェ...
おすすめ情報