2013-06-30 1 views
4

Что-то странное я заметил при сравнении boost :: lexical_cast и синтаксического анализа синтаксиса. Я пытаюсь разобрать строку в float. по какой-то причине дух дает очень неточный результат. например: при синтаксическом анализе строки «219721.03839999999», используя lexical_cast, я получаю 219721.03, который более или менее ОК. но когда я использую дух (см. код ниже), я получаю «219721.11», который далеко не в порядке. Любая идея, почему это происходит?Boost spirit floating number parser precision

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; 
} 
+1

Чтобы быть более конкретным, lexical_cast дает правильный '219721.03125', который является ближайшим действительным' float' на '219721.03839999999', а' qi :: float_' дает вам '219721.109375', что действительно не кажется правильным. – Cubbi

+1

Неотъемлемая часть номера почти насыщает емкость. То, как результат вычисляется в qi :: float_type :: parse(), таков, что «маленькие» ошибки возникают при добавлении каждого дробного числа. На самом деле это выглядит как ошибка, поскольку более умные алгоритмы не имеют этого субоптимального поведения. – sehe

+0

как мы свяжемся с этой проблемой для поддерживающих дух? – kreuzerkrieg

ответ

5

Таким образом, это будет вероятно ограничение/ошибка парсера типа «float». Попробуйте использовать парсер double_.

#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; 
} 

Выход:
й :: double_: +219721,03839999999036
й :: float_: 219721,109375

+0

выглядит разумно, я разобрался в двойное, а затем просто отбросил возвращаемое значение в float, работал как шарм :) – kreuzerkrieg

+0

I подумайте, что вы можете просто передать переменную float в синтаксическом анализаторе, а листинг будет выполняться синтаксическим анализатором. –

+0

еще одна возможность сделать это, однако я предпочту остаться под контролем, чтобы вещи произошли с моими переменными. вы можете видеть, никто не может быть доверен :) – kreuzerkrieg

 Смежные вопросы

  • Нет связанных вопросов^_^