• 締切済み

VC6における浮動少数点数値について

chie65535の回答

  • chie65535
  • ベストアンサー率43% (8561/19458)
回答No.6

最適化により k += a; b = k - 20.0; c = k - 20.0; は b = (k += a) - 20.0; c = k - 20.0; となっています。 そして、暗黙的な型キャストにより、以下のようになります。 //部分式「(k += a) - 20.0」はすべてdouble型で計算されている //floatへの変換により精度が落ちるのは、bへの代入とkへの代入のみ //(k += a)の値そのものはdoubleの精度を保持している事に注意 b = (float)((k += a) - 20.0); //kを取り出すと、floatからdoubleへの変換が起きる //従って、この時点での部分式「(k)」は「(double)20.2」と等しくない c = (double)(float)(k) - 20.0; 簡単に言えば、上記のプログラムは b = (float)((double)20.2 - (double)0.2); c = (float)((double)(float)20.2 - (double)0.2); というプログラムと等価。 「誰がどう見ても、この2つの式は異なる」ので「結果が異なる」のは当たり前。 なお「こういう現象が起きた原因」は「最適化」にあり、言語仕様上「最適化は環境に依存し、コンパイラごとに異なる」ので、VC6のバグとは言えない。 コンパイル時に最適化を抑止しなかった事、最適化による実行結果の差異を意識しない書き方をした事を考えれば、こう書いた人間に責任があると言える。 双方で同じ結果を得たいのであれば k += a; c = 0.0;//上のkへの代入と下のkの参照をぶった切って最適化させない b = k - 20.0; c = k - 20.0; と書くか k += a; b = (double)(float)(k) - 20.0;//明示的にfloatに精度を落とさせる c = (double)(float)(k) - 20.0;//明示的にfloatに精度を落とさせる と書くか k += a;//これも最適化されて意味無くなるかも知れないが b = (0.0,k) - 20.0;//カンマ演算子で「捨て演算」をして最適化させない c = k - 20.0; と書きましょう。

関連するQ&A

  • 浮動小数点表現

    浮動小数点表現の問題で以下の実行結果を元にfloat型変数 f に与えた実数の実際に格納されているビット列を表示するプログラムを作りたいのですが、 #include<stdio.h> main() { float a; scanf("%f",&a); printf("%f",a); } この程度までしか作れません。ポインタを使ってアドレスを表示することは分るのですが…。 どなたか教えていただけると助かります。 実行結果 Size of Float : 4 byte Size of Int : 4 byte f=0.500000000000000 00111111000000000000000000000000

  • scanf関数のプログラムをgetchar関数で

    scanf関数を使って四則演算、論理輪、論理積をint、float、double型で表示するプログラムを作ったのですが これをscanf関数ではなく、getchar関数で組みなおし、関数化する課題が出ました。 そのままscanf関数のところだけを変えても型が違うというエラーが出てうまくいきません。 どうすればいいでしょうか? 一応scanf関数で組んだプログラムの一部を載せておきます。 #include <stdio.h> #include <math.h> main() { float a , b; float x[5]; printf("正の数字を2つ入力して下さい(小数点を含めて4ケタまで):\n"); for(;;) { printf("\na="); scanf("%f" , &a); if(a>=0 && a<=9999 && a) { break; } else { printf("****aに入力エラー****\n"); printf("数字は4ケタ以内の正数を入力:\n"); continue; } } for(;;) { printf("b="); scanf("%f" , &b); if(b>=0 && b<=9999 && b) { break; } else { printf("****bに入力エラー****\n"); printf("数字は4ケタ以内の正数を入力:\n"); continue; } } x[0] = a+b; x[1] = a-b; x[2] = a*b; x[3] = a/b; x[4] = a||b; x[5] = a&&b; printf("\n"); printf("int型 結果:\n足し算=%d\n" , (int)x[0]); printf("引き算=%d\n" , (int)x[1]); printf("掛け算=%d\n" , (int)x[2]); printf("割り算=%d\n" , (int)x[3]); printf("論理和=%d\n" , (int)x[4]); printf("論理積=%d\n" , (int)x[5]); printf("\n"); printf("float型 結果:\n足し算=%f\n" , x[0]); printf("引き算=%f\n" , x[1]); printf("掛け算=%f\n" , x[2]); printf("割り算=%f\n" , x[3]); printf("論理和=%f\n" , x[4]); printf("論理積=%f\n" , x[5]); ・ ・ ・ getchar(); }

  • C言語の実数型の足し算

    C言語初心者です。関数の勉強していて、実数型計算に出くわしました。 #include <stdio.h> float add(float a, float b) { return a+b; } int main(void) { float x=10.5,y=20.3; printf("%f %f\n",x,y); printf("%f\n",add(x,y)); return 0; } としたら、 10.500000 20.299999 30.799999 という結果になりました。今のところint型でずーっと勉強していたので、20.3の20.299999表記が怪しく感じられ、結果も同様に怪しく感じられます。どうして、10.5+20.3=30.8とすっっきり表示してくれないのでしょうか。

  • 浮動小数点の誤差のあわせ方

    文字列からdouble型変換で他のPGと誤差がでてしまうのですが、 なんとか同じBinaryにしたいので教えてください。 1.489を他のPGのHEXで表した結果では、 printf("1.489 = %08lx%08lx\n", atof((double)???)); >3ff7d2f1a9fbe76c 私の作ったPGでは printf("1.489 = %08lx%08lx\n", atof("1.489")); >3ff7d2f1a9fbe76d の結果になります。 丸めれば、同じになるような気がしますが、 その方法がわかりません。 SPARC でCのライブラリかなにかあるでしょうか? どうかよろしくおねがいします。

  • 浮動小数点エラー

    #include<stdio.h> main (){ float D[5][6] = { {0,0,151.9058382,111.8925551,238.1626765,145.6362657},   {0,151.9058382,0,256.9532465,317.3522119,232.5861795}, {0,111.8925551,256.9532465,0,181.0294098,114.6471}, {0,238.1626765,317.3522119,181.0294098,0,93.41311845} ,   {0,145.6362657,232.5861795,114.6471,93.41311845,0}, };   float data[100][100] ; int n=5; float sum; int i,l; for(i=1;i<=n-2;i++) { sum=0; for(l=i+2;l<=n;l++) { sum=sum+D[i][l]; } ◎ data[i]=D[i][i+1]/(sum/(n-(D+1)));  ←この行 } for (i=1;i<=n;i++){ printf("%f",data[i]); } return (0); } 上のプログラムで、◎の行に浮動小数点の不正な使用とエラーがでてしまいます。 参考書、ヘルプで調べたもののなぜエラーとなるか分かりませんでした。 解決できますでしょうか?

  • C言語 プログラミングで行詰まりました…

    標準入力(キーボード)からi,jk,nの値を入力し、次の漸化式を計算し、X_0からX_nまで求めるプログラムを作成したいのですが、うまく表示されません。どかがおかしいのかご指摘お願いします。 <漸化式> X_n=(a+b)/X_(n-1) , X_0=c(n=0) ================================================================== #include<stdio.h> float f_X(int a,int b,float c) { float y; y=(a+b)/c; return y; } int main (void) { int number,i,j; float k,l,n,X; printf("i:"); scanf("%d", &i); printf("j:"); scanf("%d", &j); printf("k:"); scanf("%f", &k); printf("n:"); scanf("%f", &n); X=k; printf("X_0= %.6f\n",X); for(number=1;number<=n;number++) { l=f_X(i,j,X); printf("X_%d= %.6f \n",number,l); X=l; } return 0; } ===================================================================

  • getcharの連続について

    6つの塩基(A、T、G、C)を入力して、それを一列に並べるというものなのですが、うまくいかないので、質問させていただきます。 #include<stdio.h> main() { char b1,b2,b3,b4,b5,b6; printf("6つの塩基を入力してください。\n"); printf("1つ目の塩基は?\n"); b1=getchar(); printf("2つ目の塩基は?\n"); b2=getchar(); printf("3つ目の塩基は?\n"); b3=getchar(); printf("4つ目の塩基は?\n"); b4=getchar(); printf("5つ目の塩基は?\n"); b5=getchar(); printf("6つ目の塩基は?\n"); b6=getchar(); printf("配列は%c%c%c%c%c%cです。\n",b1,b2,b3,b4,b5,b6); } こうすると実行したときに b1= b2=b3= b4=b5=となってうまく実行できないんですが、どうしたらよいのでしょうか? ちなみに「getcharと変数とprintfとscanfを使う」と問題の条件に書いてあるので、これだけで作れという問題ですが・・・

  • 浮動小数点の切り捨てで-0.5を-1に。

    こんにちは。 小数点以下を切り捨てたいときにキャストするために 以下のようにしたところ、 float  i ; for( i=-2.5f; i<3.5f; i+=1.0f ) {   printf( "%f %d\n", i, (int)i ) ; } -2.500000  -2 -1.500000  -1 -0.500000  0 0.500000  0 1.500000  1 2.500000  2 上記の様な結果になりましたが、これを -2.500000  -3 -1.500000  -2 -0.500000  -1 0.500000  0 1.500000  1 2.500000  2 のように-0.5なら-1にするようしたいのですが、 if文は使わずに計算だけで変換することは 可能でしょうか ?

  • コンパイル環境の違いによる、浮動少数点の違い

    不動少数(float)を使った、c言語の演算プログラムを作っています。 Aマシン(CentOS5, gcc3.4)でコンパイルした、"test_a.so"と"test_a.a"について、 Aマシンで実行した結果、両者の結果は一致します。 Bマシン(Fedora5, gcc3.0)でコンパイルした、"test_b.so"と"test_b.a"について、 Bマシンで実行した結果、両者の結果は一致します。 Aマシンで実行した結果、両者の結果が異なります。 結果の比較をすると、以下のようになります。 "test_a.so"=="test_a.a"!="test_b.so"!="test_b.a" (1)コンパイル環境と実行環境が違うと、浮動少数の演算に違いがでることがありますか? (2)コンパイル環境と実行環境が違うと、so と aに違いがでることがありますか? 上記2点について、ご存知の方いらっしゃいましたら教えてください。 お願い致します。

  • 文字列をfloatで読み込む(atoi,sscanf)。しかし、値がおかしい。

    お世話になっています。 C言語の質問です。 文字列をfloatで読み込もうとしているのですが、出力結果がおかしくて困っています。 文字列をatofで変換した場合、doubleでは上手く表示できるのですが、floatでは少数が上手く表示できません。 また、sscanfでも試したのですが、上手く表示できませんでした。 どうしても、doubleを使わずにfloatであらわしたいと考えています。 どうかこのプログラムの問題点のご指摘お願いします。 実行結果 53.196600 53.196602 53.196602 ソース #include<stdio.h> #include<stdlib.h> #include<string.h> main() { char str[100]="53.1966"; double b; float c,d; b = atof(str); printf("%f\n",b); c = (float)atof(str); printf("%f\n",c); sscanf(str,"%f",&d); printf("%f\n",d); } 開発環境 windowsXP cygwin