ページ 11

double型との比較

Posted: 2016年12月01日(木) 15:05
by aaa191
範囲内の実数と格納されている配列の要素を比較し、一致する場合はカウンタ変数を増やすというプログラムなのですが、カウンターが増えてくれません。
比較の条件判定が誤っているのでしょうか?
ご教授願います。

求める答えの例: 2.0以上3.0未満の範囲の回数は3回あった

コード:

#include <stdio.h>

int main(void)
{
	int count = 0, j;
	double i;
	double a, b, tmp;
	double wind[7] = { 2.5, 1.7, 2.1, 2.7, 3.0, 4.3, 1.9 };
	
	fprintf(stderr, "値の範囲を入力(ただし正の実数):");
	scanf("%lf %lf", &a, &b);
	if(a > b){
		tmp = a;
		a = b;
		b = tmp;
	}
	for (i=a; i<b; i=i+0.1) {
	fprintf(stderr, "**i=<<%0.3f>>", i);
		for (j=0; j<7; j++) {
			if (wind[j] == i) {
			fprintf(stderr, "\n**wind[j]=<<%0.3f>>\n", wind[j]);
				count++;
			}
		}
	}
	printf ("%0.1f以上%0.1f未満の範囲の回数は%d回あった\n", a, b, count);
	
	return 0;
}

Re: double型との比較

Posted: 2016年12月01日(木) 15:25
by みけCAT
浮動小数点数はその計算機での表現の都合上誤差が生じるため、浮動小数点数をループカウンタに用いるべきではありません。
差の絶対値が小さい値(1e-7 ~1e-10程度)未満なら等しいとみなす方法もありますが、
ある範囲に含まれる実数の数を求めるなら無駄なループを使わずに直接値が範囲に入ってるかを判定したほうがいいでしょう。
なお、実数の大小の比較も、工夫しないと予期しない結果になることがあります。

よく利用される比較方法(a, bは浮動小数点数、EPSは誤差による誤動作を減らすための小さな値)
a == b → fabs(a - b) < EPS
a < b → a + EPS < b
a <= b → a < b + EPS

Re: double型との比較

Posted: 2016年12月01日(木) 15:31
by kikanshi
#include <stdio.h>
#include <math.h>

int main(void)
{
int count = 0, j;
double i;
double a, b, tmp;
double wind[7] = { 2.5, 1.7, 2.1, 2.7, 3.0, 4.3, 1.9 };
//-------------------------------
double epsilon = 1e-10
//-------------------------------

fprintf(stderr, "値の範囲を入力(ただし正の実数):");
scanf("%lf %lf", &a, &b);
if(a > b){
tmp = a;
a = b;
b = tmp;
}
for (i=a; i<b; i=i+0.1) {
fprintf(stderr, "i=%0.3f\n", i);
for (j=0; j<7; j++) {
//-----------------------------------------
if (fabs(wind[j]-i) < epsilon) {
//-----------------------------------------
fprintf(stderr, "wind[j]=%0.3f\n", wind[j]);
count++;
}
}
}
printf ("%0.1f以上%0.1f未満の範囲の回数は%d回あった\n", a, b, count);

return 0;
}

Re: double型との比較

Posted: 2016年12月01日(木) 15:48
by Egg
オフトピック
今ふと気になってDirectXTKのSimpleMath.inlみてたら
ベクトルの同値比較オペレーターがXMVectorNearEqualではなくXMVectorEqual使われてた...
これ大丈夫なんだろうか...

Re: double型との比較

Posted: 2016年12月01日(木) 21:40
by あんどーなつ
2進数小数という概念があります。普通の小数は10進数なので、

0.1234 = 0 + 1/10 + 2/(10*10) + 3/(10*10*10) + 4/(10*10*10*10)

となりますが、

0.1010(2) = 0 + 1/2 + 0/(2*2) + 1/(2*2*2) + 0/(2*2*2*2)

となるようなものです。てっとり速くいうと、浮動小数点数は10進数小数ではなく、2進数小数の表現をします。
なので、たとえば、0.1を2進数小数に直すと、

0.1 = 0.000110011001...(2)

となり、循環小数となります。このような理由で浮動小数点同士の計算では誤差が生じる、と言われているのです。

ちなみに、2進数小数で表現可能な0.5, 0.125, 1.75などや、17, 135などの整数は浮動小数点で扱っても誤差は生じないです。

以下のサイトなどでは、10進数小数と2進数小数の変換をやってくれるみたいです。

https://note.cman.jp/convert/bit/

Re: double型との比較

Posted: 2016年12月02日(金) 10:37
by YuO
うーん,単純に,windがa以上b未満であることをループで調べればよいだけで,もともと0.1ずつ足して比較していく,という方針が間違いなのではないでしょうか。

コード:

double a, b, wind[N]; // 既知
int count = 0;
for (int i = 0; i < sizeof(wind) / sizeof(wind[0]); ++i){
    if (a <= wind[i] && wind[i] < b) ++count;
}
たぶん,本来こういうことをしたかったのではないかと。