The problem with denormals and std::stod
is that the latter is defined in terms of std::strtod
, which may set errno=ERANGE
on underflow (it's implementation-defined whether it'll do, and in glibc it does). As reminded by gcc developers, in such a case std::stod
is defined by the standard to throw std::out_of_range
.
So your proper workaround is to use std::strtod
directly, ignoring ERANGE
when the value it returns is finite and nonzero, like here:
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;
}
Note that, unlike std::istringstream
approach suggested in another answer, this will work for hexfloats too.