• 締切済み

お願いします!!

はじめまして、UAです。REDHAT 7.3 と 9をしようして、GCC3.2を使用してプログラムを書いているのですが、思い通りに動作しません。いろいろ調べて見たのですが、納得がいく答えが見つかりません。機種依存であるなら仕方ないのですが、以下のプログラムの実行についてアドバイスしていただけないでしょうか? --------foo.c--------------------- #include <stdio.h> int main() { double d = 0.3; printf("%d ",(int)(d * 10.0)); return 0; } foo.c はdoubleをINTにキャストしています。この式を判断したら、3の値が求まるはずなのですが結果は --------result------------ 2 となってしまいます。  この問題で、GCCで最適化をかけてコンパイルすると、正しい値が表示されるのですが、次のようにして、配列を利用して値を評価すると、エラーになります。つまり、dの値を0.1から、0.9まで評価して、値を表示させる。 ------foo.c------------v2 #include <stdio.h> int main() { int i; double d[] = {0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9}; for(i=0;i < 9;i++) printf("%d ",(int)(d[i] * 10.0)); return 0; } これを実行すると、-O(最適化オプション)をつけて、さらに、-ffloat-storeをつけたとしても、1 2 3 ...と表示されずに、1 2 2 3 4 5 56 8 9と表示されてしまいました。  これは、どうしておこるのでしょうか? 誰かアドバイスをお願いいたします。

みんなの回答

  • nightowl
  • ベストアンサー率44% (490/1101)
回答No.2

こんにちは。原因は浮動小数点数の誤差ですね。 tatsu99 さんのおっしゃる通り、最適化すると 定数の畳み込みが行われるのでしょう。 望み通りの結果を得るには、printf のフォーマットを変更します。 printf("%g ", d[i] * 10.0); /* キャストは不要 */ もしくは、math.h をインクルードして printf("%d ",(int)rint(d[i] * 10.0)); とし、コンパイル時に数学ライブラリをリンクしてください。 $ gcc -o foo foo.c -lm

参考URL:
http://www.linux.or.jp/JM/html/LDP_man-pages/man3/nearbyint.3.html
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.1

-Sオプションをつけるとアセンブラのソースが出力されます。 最初のソースを最適化オプション-O1-Sでアセンブラに落とすと、整数の3をprintfする命令が出力されます。一方、最適化オプションをつけないで、アセンブラにおとすと、0.3×10をそのまま計算します。 従って、実行結果が最適化した場合は3になり、最適化しない場合は、2になります。 二番目のソースを同様にアセンブラに落とした場合、 最適化をした場合でも、しない場合でも、テーブルの値(0.1,0.2等)×10の計算を行っています。 従って、この場合は、1,2,3,4,5・・・のような結果は得られません。 以上のことからgccの最適化O1を行った場合、0.3*10は3であることが明白なので、いきなり3を印字しているようです。

関連するQ&A

  • なぜgccはstdio.hをインクルードしなくてもprintfが実行できるのか

    なぜgccはstdio.hをインクルードしなくてもprintfが実行できるのでしょうか。 暗黙にインクルードされるヘッダと されないヘッダファイルの差分等あれば教えていただきたく。。 // main.c int main(){ printf("SWSW\n") ; return 0 ; } % gcc main.c % ./a.out SWSW

  • プログラミング エラー部分

    #include<stdio.h> int i=3; int foo(){ i++; return(i); } int goo(int i){ i=foo(); return(i); } main(){ printf("%d\n",goo(1)); } このままこのプログラムを入力すると main(){  のところに  型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません と出るのですが、どうやったら上手く出来るのか分かる方いましたら宜しくお願いします。 それと、加えまして 上のプログラムの中で 関数foo()と関数goo()内の変数iの有効範囲は どこからどこまでなのでしょうか。 質問2つになってしまいましたが、片方でもわかる方宜しくお願いいますm(__)m

  • c言語で大きな値の階数を求めたいのですが

    c言語で関数を用いてn!を求めるプログラムを作ったのですが、 nの値が大きくなると0という値になってしまって正しい値が出てきません。 プログラムをどの様に修正したらきちんとnの値が大きくなっても 正しく値が表示されるでしょうか? ソースはこちらです。 #include <stdio.h> int func(int i); int func(int i){ if(i == 0) return 1; else return (i*func(i-1)); } void main(){ printf("%d",func(90)); /*90!を求める*/ } よろしくお願いします。

  • C言語初心者です。

    C言語初心者です。 1^2-2^2+3^3-4^2…+99^2-100^2の値を求めるプログラムを作成したいのですが上手くいきません。 どこが足りないのですか? #include <stdio.h> int main(void) { printf("%d", 1^2 - 2^2 + 3^2 - 4^2 … + 99^2 - 100^2); return (0); } よろしくお願いします。

  • 配列要素内の数値

    #include <stdio.h> int main(void) { int arr[1]={123456789}; int *x[1]; *x = arr; printf("%d ",*(x[0])); /* 123456789 と表示*/ return 0;} 実行すると123456789と表示されるまでは分かるのですが、*(x[0])の部分を別の書き方にして、arr[0]に入ってある「123456789」という数値の千の値である6という数値のみを取り出して、表示することは可能なのでしょうか?(6000と取り出したいのではなく、6として取り出したい) 次のように数値を文字列の一つ一つを扱うかのように、扱いたいのです。*(x[0])の部分の変更だけで6を取り出せるような方法はありますか? #include <stdio.h> int main(void) { char *arr[]={"pen"}; printf("%c\n",*(arr[0]+0)); printf("%c\n",*(arr[0]+1)); printf("%c\n",*(arr[0]+2)); return 0;}

  • windowsのコンパイラーで正しく実行されたのに、gccのコンパイラーでエラーがでた

    windowsのコンパイラーで正しく実行されたのに、gccのコンパイラーでエラーがでたソースコードです。ファィル名test.c です。Linux(Red Hat9) gccです。windowsのコンパイラーはCPad for Borland C++Compilerです。 #include <stdio.h> void main() //intからvoidに変更した { int i, j; for (i=1; i<=9; i++){ printf("%2d ",i); //%2dで、iが2桁に表示 } printf("\n"); printf("***************************\n"); //この罫線もどきの書き方はダサいので工夫してください for (i = 1; i<=9; i++){ for (j = 1; j<= 9; j++) { printf("%2d ", i*j); if (j == 9) printf("\n"); //1行表示後改行 } } return; //voidにしたので0を取った! } これがLinux(RedHat9)gccでは以下のエラーが出ます。 (test.c: 関数 `main' 内: test.c:4: 警告: `main' の戻り値の型が `int' ではありません)  なぜ、同じソースコードでエラーが起こるのですか?  Linux gccでは、この場合`int' 以外の何が必要なのでしょうか? 以上よろしくお願いします。

  • for文

    整数を読み込んで、その値を0までカウントダウンしながら表示するプログラム作りたいのですが、 while文ではできたのですが、for文ではうまくいきません。 どこが間違っているのでしょうか? OS:Windows XP C++Builder X パーソナル #include <stdio.h> int main(void) { int i; int num; printf("整数を入力してください:"); scanf("%d", &num); for(i = num; i <= 0; --i) { printf("%d", i); } return 0; } 宜しくお願いします。

  •  現在、私はC言語を学んでいます。

     現在、私はC言語を学んでいます。  プログラミングの初期の初期の問題なんですが、 「Hello World」という有名なプログラムがありますよね? それについての質問です。 #include<stdio.h> main() { printf("Hello World"); return 0; } も #include<stdio.h> main(void) { printf("Hello World"); return 0; } も #include<stdio.h> int main() { printf("Hello World"); } もちゃんと表示できます。 ここで質問です。 int main(void) int main() main() main(void) はどう違うんですか? あと、 return 0; はあっても無くてもいいようなんですが どういう意味があるんでしょうか?

  • c++

    /* char03*/ #include<stdio.h> int main() { char i; for(i='!';i<='~';i++){ printf(%3d(0x%2X)--%c",i,i,i); if((1-'!'+1)%4==0 printf("\n") } printf("\n") return("\n") return 0; } if((1-'!'+1)%4==0はどういう意味でしょうか

  • 前置き・後置きインクリメント。

    いつも大変お世話になり誠にありがとうございます。 標記の件。 参考書を見て、考えましたがピンときません。 どなたか解りやすく説明してもらいませんでしょうか? 2種類のコードと実行は下記の通りです. test1.c #include <stdio.h> int main(void) { int a = 0; int b = 0; b = a++; printf("代入後にインクリメントしたのでbの値は%dです。\n", b); return 0; } C:\MinGW>gcc test1.c -o test1 C:\MinGW>test1.exe 代入後にインクリメントしたのでbの値は0です。 test2.c #include <stdio.h> int main(void) { int a = 0; int b = 0; b = ++a; printf("代入前にインクリメントしたのでbの値は%dです。\n", b); return 0; } C:\MinGW>gcc test2.c -o test2 C:\MinGW>test2.exe 代入前にインクリメントしたのでbの値は1です。 前置き・後置きインクリメントの違いを論理的に ご説明願えませんでしょうか。 ご回答の程宜しくお願い申し上げます。

専門家に質問してみよう