[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
クラスのリファレンスページには、数学関数の演算でどれくらいの誤差が発生するかの表があるようです。