LoginSignup
6
2

浮動小数点演算で数学的に正確な演算結果を期待したとして(いやしちゃダメなんだけど)裏切られる確率は型によって違うのかな

Posted at

はじめに

@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);
    }
}

floatdoubleあとついでに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.6f0.7fに一致しないことを検出しています。同様に0.1f + 0.8f0.9fに一致しないことを検出しています。以降一致しない組み合わせを出力し、確認した組み合わせ 55件中 6件一致しない組み合わせがあったことを出力しています。

doublelong 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倍となりそれに応じて一致しなかった件数も増えてる印象です。今回確認したところでは、浮動小数点演算の結果がたまたま数学的に正しい様見える確率は型の違いは影響なさそうな感じでした。

おわりに

おわりです。

6
2
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2