Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
162 views
in Technique[技术] by (71.8m points)

c++ - Is it possible to read infinity or NaN values using input streams?

I have some input to be read by a input filestream (for example):

-365.269511 -0.356123 -Inf 0.000000

When I use std::ifstream mystream; to read from the file to some

double d1 = -1, d2 = -1, d3 = -1, d4 = -1;

(assume mystream has already been opened and the file is valid),

mystream >> d1 >> d2 >> d3 >> d4;

mystream is in the fail state. I would expect

std::cout << d1 << " " << d2 << " " << d3 << " " << d4 << std::endl;

to output

-365.269511 -0.356123 -1 -1. I would want it to output -365.269511 -0.356123 -Inf 0 instead.

This set of data was output using C++ streams. Why can't I do the reverse process (read in my output)? How can I get the functionality I seek?

From MooingDuck:

#include <iostream>
#include <limits>

using namespace std;

int main()
{
  double myd = std::numeric_limits<double>::infinity();
  cout << myd << '
';
  cin >> myd;
  cout << cin.good() << ":" << myd << endl;
  return 0;
}

Input: inf

Output:

inf
0:inf

See also: http://ideone.com/jVvei

Also related to this problem is NaN parsing, even though I do not give examples for it.

I added to the accepted answer a complete solution on ideone. It also includes paring for "Inf" and "nan", some possible variations to those keywords that may come from other programs, such as MatLab.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Update Provided a simple test case that shows that Boost Spirit is capable to handle all varieties of special values in this area. See below: Boost Spirit (FTW).

The standard

The only normative information in this area that I've been able to find is in sections 7.19.6.1/7.19.6.2 of the C99 standard.

Sadly, the corresponding sections of the latest C++ standard document (n3337.pdf) doesn't appear to specify support for infinity, inf and or NaN in the same way. (Perhaps I'm missing a footnote that refers to the C99/C11 spec?)

The library implementors

In 2000, the Apache libstdcxx received a bug report stating

The num_get<> facet's do_get() members fail to take the special strings [-]inf[inity] and [-]nan into account. The facet reports an error when it encounters such strings. See 7.19.6.1 and 7.19.6.2 of C99 for a list of allowed strings.

However the subsequent discussion yielded that (at least with named locale-s) it would actually be illegal for an implementation to parse special values:

The characters in the lookup table are "0123456789abcdefABCDEF+-". Library issue 221 would amend that to "0123456789abcdefxABCDEFX+-". "N" isn't present in the lookup table, so stage 2 of num_get<>::do_get() is not permitted to read the character sequence "NaN".

Other resources

securecoding.cert.org clearly states that the following 'Compliant Code' is required to avoid parsing infinity or NaN. This implies, that some implementations actually support that - assuming the author ever tested the published code.

#include <cmath>

float currentBalance; /* User's cash balance */

void doDeposit() {
  float val;

  std::cin >> val;
  if (std::isinf(val)) {
    // handle infinity error
  }
  if (std::isnan(val)) {
    // handle NaN error
  }
  if (val >= MaxValue - currentBalance) {
    // Handle range error
  }

  currentBalance += val;
}

Boost Spirit (FTW)

The following trivial example has the desired output:

#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

int main()
{
    const std::string input = "3.14 -inf +inf NaN -NaN +NaN 42";

    std::vector<double> data;
    std::string::const_iterator f(input.begin()), l(input.end());

    bool ok = qi::parse(f,l,qi::double_ % ' ',data);

    for(auto d : data)
        std::cout << d << '
';
}

Output:

3.14
-inf
inf
nan
-nan
nan
42

Summary/TL;DR

I'm inclined to say that C99 specifies the behaviour for *printf/*scanf to include infinity and NaN. C++11, sadly appears to not specify it (or even prohibit it, in the presence of named locales).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...