c++boost-spiritlexical-cast

Boost spirit floating number parser precision


There is something strange I noticed when comparing boost::lexical_cast and boost spirit parsing. I'm trying to parse a string into float. for some reason spirit gives very imprecise result. for example: when parsing string "219721.03839999999" using lexical_cast i get 219721.03 which is more or less OK. but when I use spirit (see code below) I get "219721.11" which is far from bein OK. Any idea why it happens?

template<>
inline float LexicalCastWithTag(const std::string& arg)
{
    float result = 0;

    if(arg.empty())
    {
        throw BadLexicalCast("Cannot convert from to std::string to float");
    }

    auto itBeg = arg.begin();
    auto itEnd = arg.end();

    if(!boost::spirit::qi::parse(itBeg, itEnd, boost::spirit::qi::float_, result) || itBeg != itEnd)
    {
        throw BadLexicalCast("Cannot convert from to std::string to float");
    }

    return result;
}

Solution

  • So it will be probably limitation/bug of "float" type parser. Try to use double_ parser.

    #include<iostream>
    #include<iomanip>
    #include<string>
    #include<boost/spirit/include/qi.hpp>
    
    int main()
    {
        std::cout.precision(20);
    
        //float x=219721.03839999999f;  
        //std::cout << x*1.0f << std::endl;  
        //gives 219721.03125  
    
        double resultD;
        std::string arg="219721.03839999999";
    
        auto itBeg = arg.begin();
        auto itEnd = arg.end();
        if(!boost::spirit::qi::parse(itBeg, itEnd,boost::spirit::qi::double_,resultD) || itBeg != itEnd)
            std::cerr << "Cannot convert from std::string to double" << std::endl;
        else
            std::cout << "qi::double_:" << resultD << std::endl;
    
        float resultF;
        itBeg = arg.begin();
        itEnd = arg.end();
        if(!boost::spirit::qi::parse(itBeg, itEnd,boost::spirit::qi::float_,resultF) || itBeg != itEnd)
            std::cerr << "Cannot convert from std::string to float" << std::endl;
        else
            std::cout << "qi::float_ :" << resultF << std::endl;
    
        return 0;
    }
    

    Output:
    qi::double_:219721.03839999999036
    qi::float_:219721.109375