boost 1.72 の spirit x3 の double_ パーサを使用していたところ、どうも値がちょっとおかしい。
円周率の小数点以下16桁までの文字列 "3.1415926535897932" で試してみました。
VC14.16.27023 (Visual Studio 2017 15.9.22) 使用。
#include <boost/spirit/home/x3.hpp> #include <iomanip> #include <iostream> #include <string> double atof_x3_double_(std::string const& str) { std::string::const_iterator iter = str.begin(); double result; bool success = boost::spirit::x3::parse(iter, str.end(), boost::spirit::x3::double_, result); if (!success || iter != str.end()) throw std::runtime_error("Parse failed."); return result; } void dump(std::ostream& os, double const& x) { typedef unsigned __int64 uint64; BOOST_STATIC_ASSERT(sizeof(uint64) == sizeof(double)); os << std::hex << reinterpret_cast<uint64 const&>(x); } int main() { using namespace std; try { char const org[] = "3.1415926535897932"; // 円周率の小数点以下16桁まで double x = atof_x3_double_(org); double a = atof(org); cout << setprecision(17); cout << "org: \t" << org << endl; cout << "double_:\t" << x << '\t'; dump(cout, x); cout << endl; cout << "atof: \t" << a << '\t'; dump(cout, a); cout << endl; } catch (exception const& x) { cerr << x.what() << endl; } }
spirit に合わせて全体的に const は後置になってますが、どっちでも大丈夫です。
出力
org: 3.1415926535897932 double_: 3.1415926535897927 400921fb54442d17 atof: 3.1415926535897931 400921fb54442d18
atof を通した場合と比べて、下位1ビットの違いだけですが精度が悪いです。
なので、double_ でパースした部分を文字列として取り出して、それを std::stof に通した結果を返すパーサ my_double を定義してみました。
namespace x3 = boost::spirit::x3; struct my_double_class {}; typedef x3::rule<my_double_class, double> my_double_type; my_double_type const my_double = "my_double"; static std::string::const_iterator my_double_pos; auto const my_double_save_pos = [] (auto const& ctx) { my_double_pos = _where(ctx).begin(); }; auto const my_double_act = [] (auto& ctx) { _val(ctx) = std::stod(std::string(my_double_pos, _where(ctx).begin())); }; auto const my_double_def = x3::eps [my_double_save_pos] >> x3::double_ [my_double_act] ; BOOST_SPIRIT_DEFINE(my_double);
これで boost::spirit::x3::double_ の代わりに my_double を使えば atof と同じ値になります。効率はともかくとして。
[2020/06/12] stof だったところを stod に書き換えました。