是否可以使用输入流读取无穷大或NaN值? [英] Is it possible to read infinity or NaN values using input streams?

查看:210
本文介绍了是否可以使用输入流读取无穷大或NaN值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些输入要通过输入文件流读取(例如):



-365.269511 -0.356123 -Inf 0.000000



当我使用 std :: ifstream mystream; 从文件读取一些

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



(假设 mystream 已经打开并且文件有效),



mystream>> d1> d2> d3> d4;



mystream 处于失败状态。我会期望



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



输出



-365.269511 -0.356123 -1 -1 。我想要它输出 -365.269511 -0.356123 -Inf 0



C ++流。为什么我不能做逆过程(在我的输出中读取)?

 

 

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

输入: inf



输出:

  inf 
0:inf

另请参阅: http:/ /ideone.com/jVvei



与此问题相关的还有 NaN 解析,即使我



我添加到接受的答案在ideone的一个完整的解决方案。

解决方案

div>

Edit:为了避免在double周围使用包装器结构,我在包装器类中封装了一个 istream



不幸的是,我无法弄清楚如何避免为 double 添加另一个输入法创建的歧义。对于下面的实现,我在 istream 周围创建了一个包装器结构,并且包装器类实现了输入法。输入法确定负性,然后尝试提取双精度。

编辑:感谢您为我更好地检查错误情况。

如果失败,它会启动解析。

  struct double_istream {
std :: istream& in;

double_istream(std :: istream& i):in(i){}

double_istream& parse_on_fail(double& x,bool neg);

double_istream& operator>> (double& x){
bool neg = false;
char c;
if(!in.good())return * this;
while(isspace(c = in.peek()))in.get();
if(c ==' - '){neg = true; }
在>> X;
if(!in.fail())return * this;
return parse_on_fail(x,neg);
}
};

解析例程比我初次想象的要复杂一些,避免尝试 putback 整个字符串。

  double_istream& 
double_istream :: parse_on_fail(double& x,bool neg){
const char * exp [] = {,inf,NaN};
const char * e = exp [0];
int l = 0;
char inf [4];
char * c = inf;
if(neg)* c ++ =' - ';
in.clear();
if(!(in>> * c).good())return * this;
switch(* c){
case'i':e = exp [l = 1];打破;
case'N':e = exp [l = 2];打破;
}
while(* c == * e){
if((e-exp [1])== 2)break;
++ e; if(!(in>> * ++ c).good())break;
}
if(in.good()&& * c == * e){
switch(l){
case 1:x = std :: numeric_limits< ; double> :: infinity();打破;
case 2:x = std :: numeric_limits< double> :: quiet_NaN();打破;
}
if(neg)x = -x;
return * this;
} else if(!in.good()){
if(!in.fail())return * this;
in.clear(); - C;
}
do {in.putback(* c); } while(c--!= inf);
in.setstate(std :: ios_base :: failbit);
return * this;
}

此例程的行为与默认 double 输入是如果输入为 - 字符没有消耗,例如 - inp。失败时, - inp仍会在 double_istream 的流中,但对于常规 istream 只有inp将留在流中。

  std :: istringstream iss(1.0 -NaN inf -inf NaN 1.2); 
double_istream in(iss);
double u,v,w,x,y,z;
在>> u> v>> w。 x>> y>> z;
std :: cout<< u<< < v<< < w <
<< x<< < y < < z < std :: endl;

我的系统上面的代码片段的输出是:

  1 nan inf -inf nan 1.2 

修改:添加类似辅助类的iomanip。当>> 链中出现多次时, double_imanip p>

  struct double_imanip {
mutable std :: istream * in;
const double_imanip& operator>> (double& x)const {
double_istream(* in)>> X;
return * this;
}
std :: istream& operator>> (const double_imanip&)const {
return * in;
}
};

const double_imanip&
operator>> (std :: istream& in,const double_imanip& dm){
dm.in =& in;
return dm;
}

然后下面的代码试试:

  std :: istringstream iss(1.0 -NaN inf -inf NaN 1.2 inf); 
double u,v,w,x,y,z,fail_double;
std :: string fail_string
iss>> double_imanip()
>> u> v>> w。 x>> y>> z
>> double_imanip()
>> fail_double;
std :: cout<< u<< < v<< < w <
<< x<< < y < < z < std :: endl;
if(iss.fail()){
iss.clear();
iss>> fail_string;
std :: cout<< fail_string<< std :: endl;
} else {
std :: cout<< TEST FAILED<< std :: endl;
}

上面的输出是:

  1 nan inf -inf nan 1.2 
inf

从Drise编辑:我进行了几项修改,以接受原本不包含的Inf和nan等变体。我还将其编入了一个编译演示,可以在 http://ideone.com/qIFVo 上查看。 / p>

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 << '\n';
  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.

解决方案

Edit: To avoid the use of a wrapper structure around a double, I enclose an istream within a wrapper class instead.

Unfortunately, I am unable to figure out how to avoid the ambiguity created by adding another input method for double. For the implementation below, I created a wrapper structure around an istream, and the wrapper class implements the input method. The input method determines negativity, then tries to extract a double. If that fails, it starts a parse.

Edit: Thanks to sehe for getting me to check for error conditions better.

struct double_istream {
    std::istream &in;

    double_istream (std::istream &i) : in(i) {}

    double_istream & parse_on_fail (double &x, bool neg);

    double_istream & operator >> (double &x) {
        bool neg = false;
        char c;
        if (!in.good()) return *this;
        while (isspace(c = in.peek())) in.get();
        if (c == '-') { neg = true; }
        in >> x;
        if (! in.fail()) return *this;
        return parse_on_fail(x, neg);
    }
};

The parsing routine was a little trickier to implement than I first thought it would be, but I wanted to avoid trying to putback an entire string.

double_istream &
double_istream::parse_on_fail (double &x, bool neg) {
    const char *exp[] = { "", "inf", "NaN" };
    const char *e = exp[0];
    int l = 0;
    char inf[4];
    char *c = inf;
    if (neg) *c++ = '-';
    in.clear();
    if (!(in >> *c).good()) return *this;
    switch (*c) {
    case 'i': e = exp[l=1]; break;
    case 'N': e = exp[l=2]; break;
    }
    while (*c == *e) {
        if ((e-exp[l]) == 2) break;
        ++e; if (!(in >> *++c).good()) break;
    }
    if (in.good() && *c == *e) {
        switch (l) {
        case 1: x = std::numeric_limits<double>::infinity(); break;
        case 2: x = std::numeric_limits<double>::quiet_NaN(); break;
        }
        if (neg) x = -x;
        return *this;
    } else if (!in.good()) {
        if (!in.fail()) return *this;
        in.clear(); --c;
    }
    do { in.putback(*c); } while (c-- != inf);
    in.setstate(std::ios_base::failbit);
    return *this;
}

One difference in behavior this routine will have over the the default double input is that the - character is not consumed if the input was, for example "-inp". On failure, "-inp" will still be in the stream for double_istream, but for a regular istream only "inp" will be left in the the stream.

std::istringstream iss("1.0 -NaN inf -inf NaN 1.2");
double_istream in(iss);
double u, v, w, x, y, z;
in >> u >> v >> w >> x >> y >> z;
std::cout << u << " " << v << " " << w << " "
          << x << " " << y << " " << z << std::endl;

The output of the above snippet on my system is:

1 nan inf -inf nan 1.2

Edit: Adding a "iomanip" like helper class. A double_imanip object will act like a toggle when it appears more than once in the >> chain.

struct double_imanip {
    mutable std::istream *in;
    const double_imanip & operator >> (double &x) const {
        double_istream(*in) >> x;
        return *this;
    }
    std::istream & operator >> (const double_imanip &) const {
        return *in;
    }
};

const double_imanip &
operator >> (std::istream &in, const double_imanip &dm) {
    dm.in = &in;
    return dm;
}

And then the following code to try it out:

std::istringstream iss("1.0 -NaN inf -inf NaN 1.2 inf");
double u, v, w, x, y, z, fail_double;
std::string fail_string;
iss >> double_imanip()
    >> u >> v >> w >> x >> y >> z
    >> double_imanip()
    >> fail_double;
std::cout << u << " " << v << " " << w << " "
          << x << " " << y << " " << z << std::endl;
if (iss.fail()) {
    iss.clear();
    iss >> fail_string;
    std::cout << fail_string << std::endl;
} else {
    std::cout << "TEST FAILED" << std::endl;
}

The output of the above is:

1 nan inf -inf nan 1.2
inf

Edit from Drise: I made a few edits to accept variations such as Inf and nan that wasn't originally included. I also made it into a compiled demonstration, which can be viewed at http://ideone.com/qIFVo.

这篇关于是否可以使用输入流读取无穷大或NaN值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆