はじめに
@higashi_ncさんの投稿された記事『「0.1+0.2≠0.3」を説明できないエンジニアがいるらしい』のコメント欄に投稿されたこちらのコメント以降、実数を丸める際にdouble
より精度の低いfloat
の方が丸めた後の値が一致する確率が高いか否かで議論となっており、個人的にどちらの主張も説得力があり判断がつかないため自分で検証してみることにしました。
そんなわけで確認してみたのだった
検証するコードをC++で書いております。捨てコードなので関数名変数名ええかげんな感じです。
#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
template<typename T>
void hoge(const std::string& type, int precision)
{
std::cout << "type: " << type << std::endl;
std::cout << "precision: " << precision << std::endl;
std::cout << std::fixed << std::setprecision(precision);
const long long n = pow(10, precision);
long long err = 0;
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
auto a = static_cast<T>(i) / n;
auto b = static_cast<T>(j) / n;
auto c = static_cast<T>(i + j) / n;
if (a + b != c) {
err++;
if (err <= 20) {
std::cout << a << " + " << b << " != " << c << std::endl;
}
}
}
}
std::cout << err << "/" << n * (n + 1) / 2 << " error(s)." << std::endl << std::endl;
}
int main(void)
{
for (int precision = 1; precision <= 5; precision++) {
hoge<float>("float", precision);
hoge<double>("double", precision);
hoge<long double>("long double", precision);
}
}
float
とdouble
あとついでにlong double
について、任意の小数点以下の桁数で0
より大きく1
以下の範囲でその型で表現できる正確に近い値 2つの和と数学的な正解をその型で表現できる正確に近い値で比較し、一致するかを確認しています。
実行結果はこんな感じで出力されます。
type: float
precision: 1
0.1 + 0.6 != 0.7
0.1 + 0.8 != 0.9
0.3 + 0.4 != 0.7
0.3 + 0.6 != 0.9
0.6 + 0.8 != 1.4
0.7 + 0.9 != 1.6
6/55 error(s).
float
の型で小数点以下 1桁について確認しています。
0.1f
から1.0f
の範囲を総当たりで確認し、0.1f + 0.6f
が0.7f
に一致しないことを検出しています。同様に0.1f + 0.8f
が0.9f
に一致しないことを検出しています。以降一致しない組み合わせを出力し、確認した組み合わせ 55件中 6件一致しない組み合わせがあったことを出力しています。
double
とlong double
についても同様に出力し、小数点以下の桁数を 1から 5の範囲で出力しています。
結果を表にまとめるとこんな感じです。
小数点以下桁数 | float | double | long double |
---|---|---|---|
1 | 6 | 8 | 6 |
2 | 1071 | 1068 | 1071 |
3 | 110969 | 110928 | 110933 |
4 | 11169926 | 11169574 | 11169449 |
5 | 1118630583 | 1118631119 | 1118628359 |
小数点以下の桁数が 1増えると組み合わせの数がおよそ100倍となりそれに応じて一致しなかった件数も増えてる印象です。今回確認したところでは、浮動小数点演算の結果がたまたま数学的に正しい様見える確率は型の違いは影響なさそうな感じでした。
おわりに
おわりです。