Boost.Multiprecision 誤差の検証

[Ruby]消費税計算にはBigDecimalを使いましょう

多倍長演算10進数型で演算を行えば、浮動小数点数の誤差がなくなるという話。C++の多倍長演算ライブラリであるBoost.Multiprecisionは無誤差であるというドキュメント上の規定はとくにないのですが、実際にどうなるのか検証してみました。

まずはdouble

まず、多倍長浮動小数型を使わず、doubleでやってみます。

#include <iostream>
#include <cmath>

int main()
{
    double a = 1800.0;
    double b = 1.08;

    double result = std::ceil(a * b);
    std::cout << result << std::endl; // 1944を期待する
}

出力:

1945

期待した1944ではなく、1945が出力されました。

cpp_dec_floatを使う

次に、Boost.Multiprecisionのcpp_dec_floatを使います。Boostのバージョンは1.55.0です。

#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>

namespace mp = boost::multiprecision;

using MyFloat = mp::cpp_dec_float_100;

int main()
{
    MyFloat a = 1800.0;
    MyFloat b = 1.08;

    MyFloat result = mp::ceil(a * b);
    std::cout << result << std::endl;
}

出力:

1945

こちらも期待した1944ではなく、1945になりました。

cpp_dec_floatを文字列初期化する

使い方が間違ってるみたいなので、値を文字列にしてみます。

#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>

namespace mp = boost::multiprecision;

using MyFloat = mp::cpp_dec_float_100;

int main()
{
    MyFloat a("1800.0");
    MyFloat b("1.08");

    MyFloat result = mp::ceil(a * b);
    std::cout << result << std::endl;
}

出力:

1944

期待した結果の1944になりました。

結び

最初にも書きましたが、この結果はcpp_dec_floatが無誤差演算であることを保証するものではありません。試しにやったらこういう結果になったというだけですので、ご注意を。

rationalはまだよくわかっていないので、使っていません。

Boost.Multiprecisionのnumberクラスのリファレンスページには、数学関数の演算でどれくらいの誤差が発生するかの表があるようです。

Non-member standard library function support - number class