4

In C++, we can store denorm numbers into variables without problems:

double x = std::numeric_limits<double>::denorm_min();

Then, we can print this variable without problems:

std::cout<<std::setprecision(std::numeric_limits<double>::max_digits10)
std::cout<<std::scientific;
std::cout<<x;
std::cout<<std::endl;

And it will print:

4.94065645841246544e-324

But a problem occurs when one tries to parse this number. Imagine that this number is stored inside a file, and read as a string. The problem is that:

std::string str = "4.94065645841246544e-324";
double x = std::stod(str);

will throw an std::out_of_range exception.

So my question is: how to convert a denorm value stored in a string?

4

4 回答 4

2

我不确定我是否理解了这个问题,但是std::istringstream像这样使用:

std::string str = "4.94065645841246544e-324";
double x;
std::istringstream iss(str);
iss >> x;
std::cout << std::setprecision(std::numeric_limits<double>::max_digits10);
std::cout << std::scientific;
std::cout << x << std::endl;

...给我:

4.94065645841246544e-324
于 2013-10-28T02:50:18.570 回答
0

strtod显然,您可以atof使用cstdlib. 我怀疑这是否有保证或可移植。

于 2013-10-28T02:59:32.220 回答
0

我不确定它是否会有所作为,但您实际上是在打印:

(std::numeric_limits<double>::max_digits10 + 1) = 18十进制数字。

例如,具有往返精度的 IEEE-754 64 位双精度数"1.16"采用科学计数法。也许这是引入了一些干扰转换的 ULP / 四舍五入?

于 2013-10-28T07:03:48.497 回答
0

denormals 的问题std::stod在于后者是根据 定义的std::strtod,它可能会设置errno=ERANGE为下溢(它是否会执行由实现定义,而在 glibc 中它会执行)。正如gcc 开发人员所提醒的那样,在这种情况下std::stod是由标准定义的 throw std::out_of_range

因此,您正确的解决方法是std::strtod直接使用,忽略ERANGE它返回的值是有限且非零时,如下所示:

double stringToDouble(const char* str, std::size_t* pos=nullptr)
{
    errno=0;
    char* end;
    const auto x=std::strtod(str, &end);
    if(errno==ERANGE)
    {
        // Ignore it for denormals
        if(x!=0 && x>-HUGE_VAL && x<HUGE_VAL)
            return x;
        throw std::out_of_range("strtod: ERANGE");
    }
    else if(errno)
        throw std::invalid_argument("strtod failed");
    if(pos)
        *pos=end-str;
    return x;
}

请注意,与另一个答案std::istringstream中建议的方法不同,这也适用于 hexfloats。

于 2018-07-06T06:32:27.217 回答