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

时间:2012-09-14 08:54:24

标签: c++ double ieee-754

是否有一种很好的方法可以从字符串中读取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 ++ - 方式数字阅读。

1 个答案:

答案 0 :(得分:1)

那么,你现在的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 ++,并且很有趣。 我确信可以做出改进,我只是在说明一个想法。