Looking at the documentation for strtod
:
Linux:
An infinity is either "INF" or "INFINITY", disregarding case.
OS X:
If the portion of the string following the optional plus or minus sign begins with ``INFINITY'' ... it is interpreted as an infinity
I'm using a stringstream
to convert a string
to a double
, and (wrongly) assumed that strtod
was being used behind the scenes. Neither clang++ 3.4 nor g++ 4.8 converts "INFINITY" to inf
. Only clang++ seems to convert "INF" to inf
.
Am I assuming too much about the operation of stringstream
's operator>>
? Or maybe I'm failing to check an important error condition? My test code is below (g++ -std=c++11 -Wall -Wextra inf.cpp -o inf
).
#include <cmath>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <sstream>
void
doTest(
const std::string &str)
{
double val1 = std::strtod(str.c_str(), nullptr);
std::cout << str << " - std::isinf from strtod: " << std::boolalpha <<
std::isinf(val1) << '\n';
std::stringstream sstream(str);
double val2;
sstream >> val2;
std::cout << str << " - std::isinf from stringstream: " <<
std::boolalpha << std::isinf(val2) << '\n';
std::cout << val1 << " vs " << val2 << '\n';
std::cout << std::endl;
}
int
main()
{
doTest("INFINITY");
doTest("+INF");
return (0);
}
clang++ 3.4 (OS X 10.9.2):
INFINITY - std::isinf from strtod: true
INFINITY - std::isinf from stringstream: false
inf vs 0
+INF - std::isinf from strtod: true
+INF - std::isinf from stringstream: true
inf vs inf
g++ 4.8:
INFINITY - std::isinf from strtod: true
INFINITY - std::isinf from stringstream: false
inf vs 0
+INF - std::isinf from strtod: true
+INF - std::isinf from stringstream: false
inf vs 0
I went through the standard, and the stream operator should be defined in terms of the C function strtod
, but only after filtering anything which could become Not-a-Number or infinity in Stage 2.
Following the document trail:
27.7.2.2.2 Arithmetic extractors
As in the case of the inserters, these extractors depend on the locale’s num_get<> (22.4.2.1) object to perform parsing the input stream data. These extractors behave as formatted input functions (as described in 27.7.2.2.1). After a sentry object is constructed, the conversion occurs as if performed by the following code fragment:
typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
iostate err = iostate::goodbit;
use_facet< numget >(loc).get(*this, 0, *this, err, val);
setstate(err);
22.4.2.1.2 num_get virtual functions
Stage 2: If
in==end
then stage 2 terminates. Otherwise a charT is taken from in and local variables are initialized as if by
char_type ct = *in;
char c = src[find(atoms, atoms + sizeof(src) - 1, ct) - atoms];
if (ct == use_facet<numpunct<charT> >(loc).decimal_point())
c = ’.’;
bool discard = ct == use_facet<numpunct<charT> >(loc).thousands_sep()
&& use_facet<numpunct<charT> >(loc).grouping().length() != 0
where the values src and atoms are defined as if by:
static const char src[] = "0123456789abcdefxABCDEFX+-";
char_type atoms[sizeof(src)];
use_facet<ctype<charT> >(loc).widen(src, src + sizeof(src), atoms);
for this value of loc.