• ベストアンサー

キャスト

double i; for(i = 1.0; (int)i<=10; i+=0.1){ printf("%lf %d\n",i,(int)i); } 上のようなソースで 1.0 から 10.9 まで 0.1 刻みで小数を表示しようとしたのですが、 条件式 (int)i<=10 にも関わらず出力結果に 11.0 が含まれてしまうのは何故でしょうか。

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

  • ベストアンサー
  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

double型のコンピュータ内での内部表現は2進数(基数が2の浮動小数点数)です。 0.1は10進数ではきりの良いという小数ですが 2進数では無限小数(循環小数)になり 無限に桁を保持することはできないので 途中で丸められてしまいます。(丸めは四捨五入と同等の処理です。) ここで誤差が発生するため思っているような出力結果にならなかったのでしょう。 試しにそのコードを私の環境で実行し、 printfで小数点以下15桁まで出力してみたところ 最後の11.0は正確には 10.999999999999979 でした。 参考: http://e-words.jp/w/E4B8B8E38281E8AAA4E5B7AE.html http://ja.wikipedia.org/wiki/%E6%B5%AE%E5%8B%95%E5%B0%8F%E6%95%B0%E7%82%B9%E6%95%B0

tanakarakusamoti
質問者

お礼

コードを実行までして頂き本当にありがとうございます。 とても分かりやすいご説明でした。 丸め誤差を考慮しつつ、これからは加算の順序も工夫していきたいと思います。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (2)

回答No.3

演算誤差のため、最後が11より'ほんの少し'でも小さかったら、 intにキャストすると切り捨てられて10になります。

tanakarakusamoti
質問者

お礼

画面に表示される数字の小数部分よりも更に精度の高いところで誤差が発生するんですね。 今後は気をつけます。 ご回答ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
回答No.2

 doubleなどの浮動小数点型は値によっては厳密に正確な値を表現することが出来ません。  特に 0.1などの正確に表現できない値を加算・減算を繰り返すと値の精度は計算の度に劣化して行きます。  このあたりは「浮動小数点」「誤差」で検索してみると解説しているページが幾つも見つかると思います。  このケースの場合、printfによる表示では 11.0になっていても実際の iの値は 10.99999999999と限りなく 11に近いけれども 11未満の値になっていると思われます。  for文を (ii=1.0; ii<10.91; ii+=0.1) にすれば 11.0正しく表示されると思いますが、後半の値は若干の誤差を含んでいるので、計算にはほとんど支障はないはずですが、比較などでは注意が必要です。

tanakarakusamoti
質問者

お礼

浮動小数点型では0.1はキリ良く認識されてないんですね。勉強になりました。 ご回答ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • C言語のポインタのプログラムについての質問です。

    C言語のポインタについて質問です。 nこの配列データaを受け取り、それらの値をもとに、2つのデータを引数で受け取って交換する関数void swap(double *a,*b)を用いることにより最終的に降順に並べ替えて出力したのち、それらを平均(average)と標準偏差(standard deviation)を引数で受け渡す関数 void calc_ave_stddev(int n,double a[],double *ave,double*stddev)を利用して出力されるプログラムを教えてほしいです。 main関数内での書式は printf("enter n:"); scanf("%d,&n"); for(i=0;i<n;i++){ printf("enter a[%d]:",i); scanf("%lf"&a[i]); } main関数での結果の出力は、 for(i=0;i<n;i++){ printf("a[%d]=%lf\n",a[i]); } printf("ave=%lf stddev=%lf\n",ave,stddev); です。

  • Cプログラミング

    #include <stdio.h> main(){ int i; int n; double data[100]; double total; double average; printf ("# of data ="); scanf ("%d" , &n); for (i = 0; i < n; i++){ printf("data[%d] = ", i+1); scanf("%lf" , &data[i]); } total = 0; for (i = 0; i < n; i++){ total = total +data[i]; } average = total / n; printf("total = %g\n", average); for (i = 0; i < n; i++){ printf("data[%d] : %6.1f %%\n" , i+1, (data[i] - average) / average * 100.0); } } 上のプログラムに対し、増加率の代わりに標準偏差を計算し出力するように改造せよ。という課題が出たのですが、標準偏差の計算の仕方が分かりません。教えてください。 よろしくお願いします。

  • C++の打切り誤差についてお聞きしたいのですが・・

    ↓のプログラムが、なぜ実行結果のsumが1ではなく1.000054や9.99999999999906e-001、9.9999999999990619e-001といった答えにになってしまうのでしょうか? 10000のところを512でやった場合は普通に1と出力されたのに・・・ #include <stdio.h> int main(void){ int i; float f; double d; f = 0.0; for(i = 0; i<10000; i++) { f += 1.0/10000; } printf("float: n=%d sum=%f\n", 10000, f); d = 0.0; for(i = 0; i<10000; i++) { d += 1.0/10000; }// end for printf("double:16.14e: n=%d sum=%16.14e\n", 10000, d); printf("double:18.16e: n=%d sum=%18.16e\n", 10000, d); return 0; } 実行結果 float: n=10000 sum=1.000054 double:16.14e: n=10000 sum=9.99999999999906e-001 double:18.16e: n=10000 sum=9.9999999999990619e-001 続行するには何かキーを押してください . . .

  • 2×2行列の掛け算をするプログラム

    タイトルのプログラムなんですが、授業で例題としてソース渡されたんですが、学校のUNIXのやつだと動くんですけど、自分の使ってるVC++だと動かないんですよ。 その理由と、VC++で動くようにするにはどうしたらいいかおしえてください。 ソースは、 #include<stdio.h> void get_data(); void write_data(); void product(); main() { double a[2][2],b[2][2],c[2][2]; get_data(a); get_data(b); write_data(a); write_data(b); product(a,b,c); write_data(c); } void get_data(double p[][2]) { int i,j; printf("Input elements\n"); for(i=0;i<2;i++) for(j=0;j<2;j++){ printf("(%d,%d)-th element=",i,j); scanf("%lf",&p[i][j]); } } void write_data(double p[][2]) { int i,j; printf("\n"); for(i=0;i<2;i++){ for(j=0;j<2;j++) printf("(%d,%d)-th element=%lf\t",i,j,p[i][j]); printf("\n"); } printf("\n"); } void product(double u[][2],double v[][2],double w[][2]) { int i,j,k; for(i=0;i<2;i++) for(j=0;j<2;j++){ w[i][j]=0.0; for(k=0;k<2;k++) w[i][j]+=u[i][k]*v[k][j]; } } です。 よろしくおねがいします。

  • doubleからfloatにすると表示が変になる

    しょうもない質問ですいません。 下記のC言語の行列積のコードでは行列の変数をdoubleとしていますが、これをfloatに全て置き換えると、printfで表示させる結果がバグってしまいます。 原因は何でしょうか? 最近ひさしぶりにC言語を触ったので、しょうもないところでつまずきました。 お願いします。 ----------------------------------------- #include <stdio.h> #include <stdlib.h> #define N 10 //N次の正方行列まで扱えるようにする void matrixmultiply(int n,double a[N][N],double b[N][N],double c[N][N]); int main(int argc, char** argv) { int i,j,n; double A[N][N],B[N][N],C[N][N]; FILE *readin1,*readin2; /*行列の値が書き込まれたファイルを開く*/ if((readin1=fopen("a.dat","r"))==NULL) { printf("a.datを開けません\n"); exit(1); } if((readin2=fopen("b.dat","r"))==NULL) { printf("b.datを開けません\n"); exit(1); } printf("行列の次数を入力してください\n"); scanf("%d",&n); printf("%d次の正方行列の掛け算を行います\n\n",n); /*ファイルから数値を読み込み、配列に代入する*/ for(i=0;i<n;i++) { for(j=0;j<n;j++) { fscanf(readin1,"%lf",&A[i][j]); fscanf(readin2,"%lf",&B[i][j]); } } matrixmultiply(n,A,B,C); //関数を呼び出し行列の掛け算を行う。 /*結果を表示する*/ printf("計算結果\n"); for(i=0;i<n;i++) { for(j=0;j<n;j++) { printf("%lf ",C[i][j]); } printf("\n"); } fclose(readin1); fclose(readin2); return 0; } /*掛け算を行う行列2つと、結果を入れる行列を引数として受け取る。*/ void matrixmultiply(int n,double a[N][N],double b[N][N],double c[N][N]) { int i,j,k; /*受け取った2つの行列の掛け算を行う。*/ for(i=0;i<n;i++) { for(j=0;j<n;j++) { for(k=0;k<n;k++) { c[i][j]+=a[i][k]*b[k][j]; } } } }

  • Gaussの消去法のプログラムなんですがこれを利用して、消去法による行

    Gaussの消去法のプログラムなんですがこれを利用して、消去法による行列式の計算プログラムをつくりたいのですが難しくてよくわかりません。。。 教えていただきたいです。 困ってるのでよろしくお願いします。 int gauss(double *x, double *a, double *b, int n) { int i,j,k,m; double tmp,p,sum; for(k=0; k<n-1;k++){ printf("---- Step %d ----\n",k+1); printf("-- before --\n"); for( m = k;m < n;m++){ printf("%lf\n",a[n * m + k]); } printf("-- --\n"); j = pivot(a,n,k); if(j == ERROR) { return ERROR; } else { if(j != k) { for(i=0; i<n; i++){ tmp = a[n*k+i]; a[n*k+i] = a[n*j+i]; a[n*j+i] = tmp; } tmp=b[j]; b[j]=b[k]; b[k]=tmp; } } printf("-- after --\n"); for( m = k;m < n;m++){ printf("%lf \n",a[n * m + k]); } for(i=k+1; i<n; i++){ p=a[n*i+k]/a[n*k+k]; for(j=0; j<n; j++){ a[n*i+j]=a[n*i+j]-p*a[n*k+j]; printf("a[%d %d]=%lf",i,j,a[n*i+j]); } b[i]=b[i]-p*b[k]; printf("b[%d]=%lf\n",i,b[i]); } printf("k=%d\n",k); /*--------------------------------------------------------------------------*/ } /* step 2: 後退代入 */ for(k=n-1; k>=0; k--){ if(fabs(a[n*k+k]) < EPS){ return(ERROR); } sum=0.0; for(j=k+1; j<n; j++){ sum+=a[n*k+j]*x[j]; } x[k]=(b[k] - sum)/a[k*n+k]; } return 0; } int pivot(double *a, int n, int k) { int i,m; double d; /* ピボットの探索 */ m = k; d = fabs(a[k*n+k]); for(i=k+1; i<n; i++){ if(fabs(a[n*i+k]) > d){ m = i; d = fabs(a[n*i+k]); } } if(fabs(d) < EPS) { return ERROR; } else { return m; } }

  • C言語に詳しい方、教えていただけませんか?

    n個の実数をキーボードから入力して総和を求めるプログラムを書いたのですが、結果が+NANとなってしまいます。 また、値をキーボードから入力する際、小数にするとすぐにプログラムが終了してしまいます。例えば、a[0]=1.0とすると、 a[1]=a[2]=a[3]=a[4]=合計は+NANと表示され終了してしまいます。 ちゃんと小数を入力でき、結果も正しく表示されるように間違いを指摘していただけませんか?よろしくお願いします。 (nは5としました) #include <stdio.h> #define n 5 double souwa(double a[n]); int main(void) { int i; double sum, a[n]; for(i=0; i<=n-1; i++){ printf("a[%d] = ",i); scanf("%d",&a[i]); } sum = souwa(a); printf("合計は%f\n",sum); return 0; } double souwa(double a[n]) { int i; double sum = 0.0; for(i=0; i<=n-1; i++){ sum += a[i]; } return sum; }

  • C++についての質問です

    プログラミング初心者です 以下の通りに正方行列の積を求めるプログラムを作成したのですが、うまくいきません。 #include<stdio.h> #define DTM 20 void InputMatrix(double[][DTM], int, char); void PrintMatrix(double[][DTM], int, char); void MatrixMulti(double[][DTM], double[][DTM], double[][DTM], int); int main(void) { double matrixA[DTM][DTM]; double matrixB[DTM][DTM]; double matrixC[DTM][DTM]; int n; printf("正方行列の積を求めるプログラムです\n"); printf("正方行列の次元を入れてください(<=20):"); scanf_s("%d", &n); InputMatrix(matrixA, n, 'A'); InputMatrix(matrixB, n, 'B'); MatrixMulti(matrixA, matrixB, matrixC, n); printf("\n行列 C =A×B\n"); PrintMatrix(matrixC, n, 'C'); return 0; } void InputMatrix(double a[][DTM], int n, char ch) { int i, j; printf("行列 %cの入力\n", ch); for (i = 0; i < n;i++) { for (j = 0;j < n;j++) { printf("%c[%d][%d] =", ch, i + 1, j + 1); scanf_s("%lf", &a[i][j]); } } } void PrintMatrix(double a[][DTM], int n, char ch) { int i, j; printf("行列 %c の出力\n", ch); for (i = 0;i < n;i++) { for (j = 0;j < n;j++) { printf("%5.2f\t", a[i][j]); } printf("\n"); } } void MatrixMulti(double a[][DTM], double b[][DTM], double c[][DTM], int n) { int i, j, k; for (i = 0;i < n;i++) { for (j = 0;j < n;j++) { c[i][j] = 0; for (k = 0;k < n;k++) { c[i][j] =a[i][k] * b[k][j]; } printf("%5.2f\t",c[i][j]); } printf("\n"); } }

  • c言語で、繰り返し文の中で、0.01づつ増やすには?

    c言語で、繰り返し文の中で、0.01づつ増やすには? c言語で、繰り返し文の中で、0.01づつ増やすにはどうすればよいのでしょうか? 関数F(x)=x3+2x-1 の値でx=0から5まで0.01刻みで増やし、出力させる プログラムを作成せよ。という問題です。 #include <stdio.h> int main() { double i; for(i=0;i<=5;i+=0.01){ printf("%lf",i*i*i+2*i-1); putchar('\n'); } return(0); } で、はじめにi=0なので、はじめは-1のはずですが、なぜか初めの値が11.28…と表示されます。これを0.1刻みで i+=0.1 とすると正常に作動するのですがどうでしょうか? お願いします。

  • C言語:アウトプット引数のキャストについて

    以下のサンプルソースのように、(1)の場合、出力結果が24にならないのはなぜでしょうか?基礎的な質問だと思いますがよろしくお願いします。 --------------------------------------- サンプルソース #include <stdio.h> int getValue(unsigned short* us){ *us = 24; } main(){ int ret = 0; int intVal = 0; unsigned short usVal = 0; /* (1)int型のintValをunsigned short型にキャストした場合 */ ret = getValue((unsigned short*)&intVal); printf("%d\n", intVal); /* (2)unsigned short型のusValをそのまま引数に渡した場合 */ ret = getValue(&usVal); printf("%d\n", usVal); } ---------------------------------- 出力結果 1572864 ←(1)の結果 24 ←(2)の結果 -----------------------------------

保存できません
このQ&Aのポイント
  • 名刺の原稿を作成して保存しようとしたところ、「RangeError:Array buffer allocation failed」というエラーが表示されます。
  • らくちんプリントを使用して名刺の原稿を作成し、保存しようとすると、「RangeError:Array buffer allocation failed」というエラーメッセージが表示されます。
  • エレコム株式会社の製品であるらくちんプリントを使用して名刺の原稿を作成しようとすると、保存時に「RangeError:Array buffer allocation failed」というエラーが表示されます。
回答を見る