从字符串中读取溢出双倍作为'inf'的安全方法

Safe way to read overflowed double as 'inf' from string

本文关键字:inf 方法 安全 字符串 读取 溢出      更新时间:2023-10-16

有没有一种很好的方法可以从溢出的字符串中读取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++路数字读数。

好吧,你目前的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++式的,而且很有趣。我相信可以做出改进,我只是在说明一个想法。