導入
C++で数値を扱う際、浮動小数点型(floatやdouble)を使用して計算を行ったとき、期待した値とわずかに異なる結果が出たことはありませんか?これは「丸め誤差」と呼ばれる現象で、金融計算や精密な比較処理において致命的なバグを引き起こす可能性があります。本記事では、なぜこのような誤差が生じるのか、そしてどのように対処すべきかを解説します。
基礎知識
コンピュータは内部的に数値を2進数で扱っています。私たちが普段使う10進数の小数は、2進数に変換すると「0.1」のように単純な数値であっても、無限小数になってしまうことがほとんどです。浮動小数点型は有限のメモリ領域(ビット数)に値を格納するため、無限小数の端数を切り捨てたり四捨五入したりして保存します。この際、元の10進数との間に微小なズレが生じます。これが「丸め誤差」の正体です。
実装/解決策
浮動小数点の比較において、「==」演算子を使用してはいけません。代わりに、2つの値の差が十分に小さいか(許容誤差以内か)をチェックする手法を用います。この許容誤差は一般的に「イプシロン(EPSILON)」と呼ばれます。
サンプルプログラム
以下のコードは、誤差が原因で比較が失敗するケースと、許容誤差を用いた正しい比較方法の例です。
include <iostream>
include <cmath> // std::absを使用するため
int main() {
double a = 0.1;
double b = 0.2;
double c = 0.3;
// 誤差があるため、0.1 + 0.2 は 0.3 と完全には一致しない
if (a + b == c) {
std::cout << "一致しました" << std::endl;
} else {
std::cout << "一致しませんでした(丸め誤差の影響)" << std::endl;
}
// 許容誤差(イプシロン)を定義して比較する
const double EPSILON = 1e-9;
if (std::abs((a + b) - c) < EPSILON) {
std::cout << "許容誤差の範囲内で一致とみなします" << std::endl;
}
return 0;
}
応用・注意点
注意点:
1. 厳密な精度が必要な場合: 金額計算など、1円のズレも許されない処理では、浮動小数点型(float/double)を使ってはいけません。その場合は、数値を整数(intやlong long)として扱い、単位を変換して計算する(例:円を銭に変換する)か、多倍長整数ライブラリを使用してください。
2. EPSILONの選択: 扱う数値の大きさに応じて適切なイプシロンを設定してください。非常に大きな数値や非常に小さな数値を比較する場合、固定のイプシロンでは不十分な場合があります。
3. 比較の基本: 可能な限り「==」ではなく、不等号(< や >)による範囲チェックを活用する設計を心がけるのが、バグを減らす近道です。

コメント