【C++学習|初心者向け】浮動小数点数の比較でハマらないために!std::numeric_limits::epsilon() の使い方

導入: なぜ浮動小数点数の比較は難しいのか

C++でプログラミングをしていると、if (a == b) のような比較処理をよく書きますよね。しかし、doubleやfloatといった「浮動小数点数」を使った計算で、この書き方をしてしまうと、意図した通りに動作しないことがあります。
例えば、0.1 + 0.2 は人間から見れば 0.3 ですが、コンピュータの内部計算ではごくわずかな誤差が生じ、0.30000000000000004 といった値になるからです。
この「計算の微妙なズレ」を解決し、安全に値を比較するために欠かせないのが、今回紹介する std::numeric_limits::epsilon() です。

基礎知識: epsilon(イプシロン)とは何か

std::numeric_limits::epsilon() は、その型(T)において「1.0 と、それより大きい最小の値との差」を返す関数です。
簡単に言うと、「この型で表現できる、無視できないほど小さな値」のことです。
浮動小数点数は、巨大な数や非常に小さな数を扱うために、精度に限界があります。計算結果が完全に一致するかどうかを調べるのではなく、「誤差の範囲内であれば同じとみなす」というアプローチをとるために、この値を「許容誤差(しきいち)」として利用します。

実装/解決策: 誤差を許容した比較方法

直接 == で比較するのではなく、2つの値の「差の絶対値」を計算し、それが epsilon() より小さいかどうかをチェックします。
C++の標準ヘッダである を使用します。

サンプルプログラム: epsilonを使った安全な比較

以下のコードをコピーして、動作を確認してみてください。

#include
include include // std::absを使用するために必要

int main() {
double a = 0.1 + 0.2;
double b = 0.3;

// 1. NGな例:厳密に一致するかを確認している
if (a == b) {
std::cout << "一致しました!" << std::endl; } else { std::cout << "NG: 一致しませんでした。" << std::endl; } // 2. OKな例:epsilonを使って誤差の範囲内かを確認 // 2つの値の差が、非常に小さい値(epsilon)以下なら同じとみなす double diff = std::abs(a - b); if (diff < std::numeric_limits::epsilon()) {
std::cout << "OK: 誤差の範囲内で一致しました!" << std::endl; } return 0; }

応用・注意点: 現場での活用と落とし穴

1. 比較する値の大きさに注意する
今回紹介した epsilon() は、値が 1.0 前後の時に最も効果的です。もし扱う値が非常に大きい(例: 1,000,000)場合、epsilon() をそのまま使うと小さすぎて判定がうまくいかないことがあります。その場合は、値をスケーリング(倍率をかける)して判定する必要があります。

2. std::abs を忘れない
差を判定する際は、必ず std::abs を使って「絶対値」にしてください。どちらの数値が大きいかによって引き算の結果が負の値になると、比較が正しく行えなくなります。

3. 厳密な数値計算には向かない
もし、お金の計算のように「誤差が絶対に許されない」処理を扱う場合は、浮動小数点数(doubleやfloat)ではなく、整数型(intやlong long)で「円単位」にするか、多倍長整数ライブラリを使うことを検討してください。

まずは、浮動小数点数同士の比較で「==」を使いたくなったら、「あ、epsilonを使うべき場面かな?」と思い出せるようになれば、バグを未然に防げるエンジニアへの第一歩です!

コメント

タイトルとURLをコピーしました