cpp:comparison-operator

変数に読み込んだ値は、比較ができます。これはほとんどのプログラミング言語で共通です。 CPUはプログラム中で値を比較するときは、それぞれ持っているレジスタ同士で比較します。プログラミング言語で比較を行うときもCPU様に気を使って書かなければならないため、(基本的に)一度に2つのものの比較しかできません。

比較は、C++の組み込み型(初めから使える型)の同じ型同士であれば大抵は可能である。 比較は、以下の比較用の演算子(比較演算子)を用いて行う。

名称 演算子 構文
小なり < a < b
小なりイコール <= a <= b
大なり > a > b
大なりイコール >= a >= b
非等価 != a != b
等価 == a == b

等価比較

入力した符号付整数が10かどうか判定する 判定式がtrueならその数を表示(10だよね) (それ以外(falseの時)は何もしない)

#include <iostream>
 
int main()
{
    int num;
    std::cin >> num;
 
    if(num == 10)
    {
        //num が「10」なら true
        std::cout << num << std::endl; 
    }
    return 0;
}

等価比較

入力した浮動小数点数(double)がある数と等価かどうか判定する
とかやりたいときは注意が必要。
floatやdoubleは計算誤差が発生するので==で数とそのまま比較するのはNG

0.2
0.1
0.3






#include <iostream>
using std::cout;
using std::cin;
using std::endl;
 
int main() {
	double num1=0.2, num2=0.1;
 
	cout << num1 << endl; //num1表示
	cout << num2 << endl; //num2表示
	cout << num1+num2 << endl; //num1+num2表示
 
	if(num1+num2 == 0.3) //比較演算
	{
		cout << "num1+num2=" << num1+num2 << endl;
	}
}

このように、表示上は0.3と表示されるが(coutの機能で、0.299999が0.3に丸め込まれてる)内部的には(メモリの中では)0.3ぴったりにはなっていない。
そのため、$num1+num2 == 0.3$などと等価比較してしまうと、判定はうまくいかない。

0.20000000000000001110
0.10000000000000000555
0.30000000000000004441






#include <iostream>
#include <iomanip>
 
using std::cout;
using std::cin;
using std::endl;
 
int main() {
	double num1=0.2, num2=0.1;
 
	cout << std::fixed 
		 << std::setprecision(20) 
		 << num1 << endl; //num1表示
	cout << std::fixed
		 << std::setprecision(20) 
		 << std::setprecision(20)
		 << endl; //num2表示
	cout << std::fixed 
		 << std::setprecision(20) 
		 << num1+num2 << endl; //num1+num2表示
 
	if(num1+num2 == 0.3) //比較演算
	{
		cout << "num1+num2=" << num1+num2 << endl;
	}
}
少々考える

どうしてこのようなことが起こるか考える。
そもそも、整数はメモリ内で2進数で保存されてるが、整数と2進数の変換の間には誤差なく変換を行うことができる。
しかしながら、小数点数は、誤差なく1対1で変換することができないので、変換誤差が生じる。
ここで実際にどのように0.1や0.2がメモリに保存されているか見てみよう)
よって、それらの四則演算の結果は、数学の理論的な値と異なってくることが多く、計算機による実数計算では、様々なところで気を付けなければならない。(このような分野を扱う学問があり、専門的には数値計算法という分野になっています)

それじゃぁどうすんの?

計算誤差をどこまで許すかというのを、自分のプログラムの設計段階で決めます。
上の例を見るとわかるとおり、誤差は通常のcoutでの小数点以下1桁表示程度では判定できないくらい小さい桁で発生しています。
そのぐらい小さいとこでの誤差は許してしまおう。という解決方法です。
例えば$10^{-3}$までの誤差なら許してしまおう。 (上の例で$num1+num2$ が $0.3001$程度なら $0.3$ になってると見なそうという事)
なので、計算結果と正解の数の誤差を計算します。

fabs((num1 + num2) - 0.3)

fabsは絶対値を求める関数です。

double num1 = 0.1, num2 = 0.2;
 
if( fabs((num1 + num2) - 0.3) <= 1e-3)
{
    cout << "true" << endl;
}
まとめ

以上のことを踏まえて、誤差計算で2つの浮動小数点数の等価比較をしてみます。 許容誤差は $10^{-3}$ で計算する。
(興味があれば、std::fabs(num1+num2 - 0.3)の値が、どのくらいになるか表示してみて、誤差がどのくらい出ているか調べてみよう)

#include <iostream>
#include <iomanip>
#include <cmath>
 
using std::cout;
using std::cin;
using std::endl;
 
int main() {
	double num1=0.2, num2=0.1;
 
	cout << std::fixed 
		 << std::setprecision(20) 
		 << num1 << endl; //num1表示
	cout << std::fixed
		 << std::setprecision(20)
	     << num2 << endl; //num2表示
	cout << std::fixed 
		 << std::setprecision(20) 
		 << num1+num2 << endl; //num1+num2表示
 
	if(num1+num2 == 0.3) 
	//比較演算 == でためす
	{
		cout << "num1+num2=" << num1+num2 << endl;
	}
 
	if(std::fabs(num1+num2 - 0.3) < 1e-3) 
    //比較演算 許容誤差10^-3で誤差計算をする
	{
		cout << "num1+num2=" << num1+num2 << endl;
	}
}

非等価比較

入力した符号付整数が「10以外」かどうか判定する
判定式がtrueならその数を表示
(それ以外(falseの時つまり10の時)は何もしない)
これも、浮動小数点の時は気を付けなければいけないよね?(どうすればいいかは、もうわかるはず!)

#include <iostream>
 
int main()
{
    int num;
    std::cin >> num;
 
    if(num != 10)
    {
        //num が「10以外」なら true
        std::cout << num << std::endl; 
    }
    return 0;
}

大小比較

入力した符号付整数が10より大きいかどうかを判定する 判定式がtrueなら、入力した数を表示する (それ以外(false)の時は何もしない)

#include <iostream>
 
int main()
{
    int num;
    std::cin >> num;
 
    if(num > 10)
    {
        //num が「10より大きい」なら true
        std::cout << num << std::endl; 
    }
    return 0;
}
  • cpp/comparison-operator.txt
  • 最終更新: 3年前
  • by root