使用Visual C ++的NaN ASCII I / O [英] NaN ASCII I/O with Visual C++

查看:163
本文介绍了使用Visual C ++的NaN ASCII I / O的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用iostream和Visual C ++从/从文本文件读取和写入NaN值。当写一个NaN值时,我得到 1.#QNAN 。但是,读回它输出 1.0

  float nan = std: :numeric_limits< float> :: quiet_NaN(); 
std :: ofstream os(output.txt);

os<< nan;
os.close();

输出为 1.#QNAN

  std :: ifstream is(output.txt); 
是>> nan;
is.close();

nan 1.0



解决方案



建议由awoodland,我想出了这个解决方案。我选择nan作为NaN的字符串表示。两者<<和>>运算符被覆盖。

  using namespace :: std; 

class NaNStream
{
public:
NaNStream(ostream& _out,istream& _in):out(_out),in(_in){}
模板< typename T>
const NaNStream&运算符<<(const T& v)const {out<< v; return * this;}
template< typename T>
const NaNStream& operator>>(T& v)const {in>> v; return * this;}
protected:
ostream&出口;
istream&在;
};

// override<< float类型的操作符
模板<> const NaNStream& NaNStream :: operator<<(const float& v)const
{
//测试v是否为NaN
if(v == v)
out< v;
else
out<< nan;
return * this;
}

// override>> float类型的操作符
template<> const NaNStream& NaNStream :: operator>>(float& v)const
{
if(in>> v)
return * this;

in.clear()
std :: string str;
if(!(in>> str))
return * this;

if(str ==nan)
v = std :: numeric_limits< float> :: quiet_NaN();
else
in.setstate(std :: ios :: badbit); //糟糕,我们仍然偷走字符串

return * this;
}

最小工作示例:有限浮点和NaN写入字符串流然后读回。

  int main(int,char **)
{
std :: stringstream ss;
NaNStream nis(ss,ss);
nis<< 1.5f < std :: numeric_limits< float> :: quiet_NaN();
std :: cout<< ss.str()<< std :: endl; // OUTPUT:1.5nan

float a,b;
nis>>一个; nis>> b;
std :: cout<< a<< b<< std :: endl; // OUTPUT:1.51。#QNAN
}


解决方案>

使用C ++ 03你可以很容易地解决这个问题帮助类和你自己的运算符:

  #include< iostream> 
#include< sstream>
#include< string>
#include< limits>

struct FloatNaNHelper {
float value;
operator const float&()const {return value; }
};

std :: istream& (>> f.value)
返回;如果没有返回值,则返回true;否则返回false。

in.clear();
std :: string str;
if(!(in>> str))
return in;

//使用std :: transform低阶?
//我的平台上的NaN是这样写的。
if(str ==NaN)
f.value = std :: numeric_limits< float> :: quiet_NaN();
else
in.setstate(std :: ios :: badbit); //糟糕,我们仍然偷走字符串

return in;
}

这对我的平台上的NaN很有意义,但也说明了可移植性问题固有的 - 你的图书馆似乎代表不同,如果你想支持两者,这可能会使问题复杂化。
我用这个测试:

  int main(){
std :: istringstream in 1.0 555 NaN foo);
FloatNaNHelper f1,f2,f3;
在>> f1> f2> f3;
std :: cout<< static_cast< float>(f1)<< ,< static_cast< float>(f2)< ,< static_cast< float>(f3)<< std :: endl;

if(in>> f1)
std :: cout<< OOPS! << std :: endl;
}

您还可以将语义更改为更简洁: / p>

  int main(){
std :: istringstream in(1.0 555 NaN foo);
float f1,f2,f3;
在>> FloatNaNHelper(f1)>> FloatNaNHelper(f2)> FloatNaNHelper(f3);
std :: cout<< f1<< ,< f2<< ,< f3<< std :: endl;
}

需要更改 FloatNaNNHelper

  struct FloatNaNHelper {
float&值;
explicit FloatNaNHelper(float& f):value(f){}
};

和运算符:

  std :: istream& operator>>(std :: istream& in,const FloatNaNHelper& f); 


I want to read and write NaN values from/into text files using iostream and Visual C++. When writing a NaN value, i get 1.#QNAN. But, reading it back outputs 1.0 .

float nan = std::numeric_limits<float>::quiet_NaN ();
std::ofstream os("output.txt");

os << nan ;
os.close();

The output is 1.#QNAN .

std::ifstream is("output.txt");
is >> nan ;
is.close();

nan equals 1.0.

Solution

Finally, as suggested by awoodland, I've come up with this solution. I chose "nan" as a string representation of a NaN. Both << and >> operators are overridden.

using namespace ::std;

class NaNStream 
{
public:
  NaNStream(ostream& _out, istream& _in):out(_out), in(_in){}
  template<typename T>
  const NaNStream& operator<<(const T& v) const {out << v;return *this;}
  template<typename T>
  const NaNStream& operator>>(T& v) const {in >> v;return *this;}
protected:
  ostream& out;
  istream& in;
};

// override << operator for float type
template <> const NaNStream& NaNStream::operator<<(const float& v) const 
{
  // test whether v is NaN 
  if( v == v )
    out << v;
  else
    out << "nan";
  return *this;
}

// override >> operator for float type
template <> const NaNStream& NaNStream::operator>>(float& v) const 
{
  if (in >> v)
    return *this;

  in.clear();
  std::string str;
  if (!(in >> str))
    return *this;

  if (str == "nan")
    v = std::numeric_limits<float>::quiet_NaN();
  else
    in.setstate(std::ios::badbit); // Whoops, we've still "stolen" the string

  return *this;
}

A minimal working example: a finite float and a NaN are written into a stringstream and then read back.

int main(int,char**) 
{
  std::stringstream ss;
  NaNStream nis(ss, ss);
  nis << 1.5f << std::numeric_limits<float>::quiet_NaN ();
  std::cout << ss.str() << std::endl; // OUTPUT : "1.5nan"

  float a, b;
  nis >> a;  nis >> b;
  std::cout << a << b << std::endl;  // OUTPUT : "1.51.#QNAN"
}

解决方案

With C++03 you can fairly easily work around the issue with the aid of a helper class and your own operator:

#include <iostream>
#include <sstream>
#include <string>
#include <limits>

struct FloatNaNHelper {
  float value;
  operator const float&() const { return value; }
};

std::istream& operator>>(std::istream& in, FloatNaNHelper& f) {
  if (in >> f.value)
    return in;

  in.clear();
  std::string str;
  if (!(in >> str))
    return in;

  // use std::transform for lowercaseness?
  // NaN on my platform is written like this.
  if (str == "NaN")
    f.value = std::numeric_limits<float>::quiet_NaN();
  else
    in.setstate(std::ios::badbit); // Whoops, we've still "stolen" the string

  return in;
}

This works for NaN on my platform quite sensibly, but also illustrates the portability problem inherent there too - your library seems to represent it differently, which could complicate the issue somewhat if you wanted to support both. I used this test with it:

int main() {
  std::istringstream in("1.0 555 NaN foo");
  FloatNaNHelper f1,f2,f3;
  in >> f1 >> f2 >> f3;
  std::cout << static_cast<float>(f1) << ", " << static_cast<float>(f2) << ", " << static_cast<float>(f3) << std::endl;

  if (in >> f1)
    std::cout << "OOPS!" << std::endl;
}

You can also change the semantics of this to something possibly a little cleaner:

int main() {
  std::istringstream in("1.0 555 NaN foo");
  float f1,f2,f3;
  in >> FloatNaNHelper(f1) >> FloatNaNHelper(f2) >> FloatNaNHelper(f3);
  std::cout << f1 << ", " << f2 << ", " << f3 << std::endl;
}

Requires the changing FloatNaNNHelper:

struct FloatNaNHelper {
  float& value;
  explicit FloatNaNHelper(float& f) : value(f) { }
};

And the operator:

std::istream& operator>>(std::istream& in, const FloatNaNHelper& f);

这篇关于使用Visual C ++的NaN ASCII I / O的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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