Domanda

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).

Test Code

#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);
}

Output

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
È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top