誤差の扱い

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
pin
記事: 3
登録日時: 8年前

誤差の扱い

#1

投稿記事 by pin » 8年前

基本的なことですが、、

値1と値2の差が誤差範囲内(例えば0.01)にあるか判定する場合
1.09

1.08
は誤差範囲内にあると認識したいところですが、
システム上のdoubleの値をとると、実際にはごみが入ります。
これの差分をとって0.01と比較すれば、値によって上回ったり下回ったりするかと思います。
どのように判定するのが正しいのでしょう。。

Math

Re: 誤差の扱い

#2

投稿記事 by Math » 8年前

BCD演算(2進化10進数)[電卓はBCDなので正確]を使わないと正確な計算はできません。doubleは誤差がありすぎます。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 誤差の扱い

#3

投稿記事 by みけCAT » 8年前

浮動小数点数の計算はどうしても誤差を含むので、なるべく避けるのがいいでしょう。
例えば、入力が

コード:

1.09 1.08
のように必ず小数点以下2桁で与えられるのであれば、

コード:

#include <stdio.h>
#include <stdlib.h>

/*
読み取り成功と判定したらresultが指す場所に格納して真を返す
読み取り失敗と判定したら偽を返す
*/
int read_number(int *result) {
	int a, b;
	if (scanf("%d.%d", &a, &b) != 2) return 0;
	*result = a * 100 + b;
	return 1;
}

int main(void) {
	int atai1, atai2;
	/* ||演算子は必ず左辺から評価される */
	if (!read_number(&atai1) || !read_number(&atai2)) return 1;
	if (abs(atai1 - atai2) <= 1) {
		puts("YES");
	} else {
		puts("NO");
	}
	return 0;
}
のように100倍して整数で処理するといいでしょう。

浮動小数点数の比較には、一般に小さい値を用いて誤差の影響を減らすテクニックが用いられます。
(確実に意図した判定をするのは不可能だろうと思います)
[table=border:1px solid #cccccc; margin: 0.5em;][tr=][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]普通の比較[/td][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]浮動小数点数の比較[/td][/tr]
[tr=][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]A == B[/td][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]fabs(A - B) < EPS[/td][/tr]
[tr=][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]A < B[/td][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]A + EPS < B[/td][/tr]
[tr=][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]A <= B[/td][td=border:1px solid #cccccc; padding: 0.1em 0.2em;]A < B + EPS[/td][/tr][/table](EPSは1e-9~1e-7程度の小さな値)

コード:

#include <stdio.h>
#include <math.h>

#define EPS 1e-9

int main(void) {
	double atai1, atai2;
	if (scanf("%lf%lf", &atai1, &atai2) != 2) return 1;
	if (fabs(atai1 - atai2) < 0.01 + EPS) {
		puts("YES");
	} else {
		puts("NO");
	}
	return 0;
}
また、言語が指定されていないようなので、JavaのBigDecimalクラスを利用するのもいいかもしれません。

コード:

import java.math.BigDecimal;
import java.util.Scanner;

class Main {
	public static void main(String[] args) {
		BigDecimal atai1, atai2;
		Scanner sc = new Scanner(System.in);
		atai1 = sc.nextBigDecimal();
		atai2 = sc.nextBigDecimal();
		if (atai1.subtract(atai2).abs().compareTo(new BigDecimal("0.01")) <= 0) {
			System.out.println("YES");
		} else {
			System.out.println("NO");
		}
	}
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

pin
記事: 3
登録日時: 8年前

Re: 誤差の扱い

#4

投稿記事 by pin » 8年前

ご回答ありがとうございました。
大変勉強になりました。

返信

“C言語何でも質問掲示板” へ戻る