比較演算
変数に読み込んだ値は、比較ができます。これはほとんどのプログラミング言語で共通です。 CPUはプログラム中で値を比較するときは、それぞれ持っているレジスタ同士で比較します。プログラミング言語で比較を行うときもCPU様に気を使って書かなければならないため、(基本的に)一度に2つのものの比較しかできません。
比較は、C++の組み込み型(初めから使える型)の同じ型同士であれば大抵は可能である。 比較は、以下の比較用の演算子(比較演算子)を用いて行う。
| 名称 | 演算子 | 構文 |
| 小なり | < | a < b |
| 小なりイコール | <= | a <= b |
| 大なり | > | a > b |
| 大なりイコール | >= | a >= b |
| 非等価 | != | a != b |
| 等価 | == | a == b |
サンプルs
等価比較
入力した符号付整数が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.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.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; }