Chcę odczytać i zapisać wartości NaN z/do plików tekstowych za pomocą iostream i Visual C++. Podczas pisania wartości NaN otrzymuję 1.#QNAN
. Ale, czytając to z powrotem, wychodzi 1.0
.NaN ASCII I/O z Visual C++
float nan = std::numeric_limits<float>::quiet_NaN();
std::ofstream os("output.txt");
os << nan ;
os.close();
Dane wyjściowe to 1.#QNAN
.
std::ifstream is("output.txt");
is >> nan ;
is.close();
nan
równa 1.0
.
Rozwiązanie
Wreszcie, zgodnie z sugestią awoodland, mam wymyślić tego rozwiązania. Wybrałem "nan" jako ciąg znaków na NaN. Zarówno operatory < < jak i >> są nadpisywane.
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;
}
Minimalny przykład działania: skończony float i NaN są zapisywane w strumieniu, a następnie odczytywane.
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"
}
Pytanie powinno brzmieć: "Jak sformatować wejścia/wyjścia z NaN". Przypuszczam. Dobre pytanie. –
http://pubs.opengroup.org/onlinepubs/007904975/functions/scanf.html mówi: "Jeśli rodzina funkcji fprintf() generuje reprezentacje ciągów znaków dla nieskończoności i NaN (symboliczna encja zakodowana w formacie zmiennoprzecinkowym) do obsługują IEEE Std 754-1985, funkcje fscanf() funkcji powinny je rozpoznawać jako dane wejściowe. "niezależnie od tego, co jest warte. –
@Moo: jeśli to prawda, to przynajmniej wiemy teraz, że iostreams nie używają 'fscanf' :-) W każdym razie byłoby śmiesznie na czym polegać, ponieważ tekstowa reprezentacja NaN różni się od kompilatora do kompilator i prawdopodobnie również ze stanu. Może po prostu nie można * przeczytać * NaN. (Nie ma nawet żadnego dosłownego, żeby o tym pomyśleć.) –