Безопасный способ прочитать переполненный double как ‘inf’ из строки

Есть хороший способ читать double из строки относительно переполнения, то есть конвертировать "1e500" -> +inf ?

Способы чтения из строки мне известны:

  • ::std::stringstream — возвращает мусор при переполнении;
  • ::boost::lexical_cast — брошенный bad_lixecal_cast без достойной информации о конвертируемом числе
  • ::std::strtod от cstdlib — afaik это единственный, который сообщает о переполнении (возвращая HUGE_VAL и настройка errno в ERANGE), но использовать его тихо неудобно

В частности, мне нужен метод, чтобы надежно преобразовать строку в число (double), например

"1e100" -> 1e100
"1e300" -> 1e300
"1e309" -> +inf // handling overflow as ieee-754 'inf'

РЕДАКТИРОВАТЬ:

Я на самом деле использую последний подход, вот код:

double stringToDouble(char const *str)
{
double result = ::std::strtod(str, 0);

if (ERANGE == errno)
{
if (HUGE_VAL == result)
{
result = INFINITY;
}
else if (-HUGE_VAL == result)
{
result = -INFINITY;
}
}

return result;
}

Я был довольно удивлен, что stringstream не справляется с переполнением Но это на самом деле возвращает какой-то другой double значение (не связано с тем, что читается), и сообщает только через stream :: fail ().

Но все же я ищу немного C ++ — способ чтения чисел.

2

Решение

Что ж, ваш нынешний способ работы в C намного эффективнее, чем я собираюсь предложить, но, поскольку вы запрашиваете метод C ++, вот один из них — определение объекта, похожего на манипулятор, для защиты вас от переполнений:

#include "stdafx.h"#include <iostream>
#include <string>
#include <limits>
#include <algorithm>

using namespace std;

struct OverflowProtect
{
} limitdouble;

struct DoubleOverflowException : public std::exception
{

};

double stringToDouble(char const *str)
{
double result = ::std::strtod(str, 0);

if (ERANGE == errno)
{
if (HUGE_VAL == result)
{
throw DoubleOverflowException(); // throw whatever exception you want here
}
else if (-HUGE_VAL == result)
{
throw DoubleOverflowException(); // throw whatever exception you want here
}
}

return result;
}

istream & operator >> (istream & aIn, const OverflowProtect & aManip)
{
string number;
aIn >> number;

stringToDouble(number.c_str());

for_each(number.rbegin(), number.rend(), [&aIn](char c){aIn.putback(c);});

return aIn;
}

int _tmain(int argc, _TCHAR* argv[])
{
double nr;
try
{
cin >> limitdouble >> nr;
}
catch ( DoubleOverflowException & e )
{
// handle overflow exception thrown by limitdouble
e;
}

return 0;
}

Не самый эффективный способ, особенно operator>> реализация, но, несомненно, C ++ — как, и очень весело.
Я уверен, что улучшения могут быть сделаны, я просто иллюстрирую идею.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector