gpt4 book ai didi

c++ - 使用 Visual C++ 的 NaN ASCII I/O

转载 作者:IT老高 更新时间:2023-10-28 22:13:02 27 4
gpt4 key购买 nike

我想使用 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");
is >> nan ;
is.close();

nan 等于 1.0

解决方案

最后,按照 awoodland 的建议,我想出了这个解决方案。我选择“nan”作为 NaN 的字符串表示。 << 和 >> 运算符都被覆盖。

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

一个最小的工作示例:一个有限 float 和一个 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 >> a; nis >> b;
std::cout << a << b << std::endl; // OUTPUT : "1.51.#QNAN"
}

最佳答案

打印 float 时或 double值为 std::ostream ,类模板std::num_put<>使用 (C++03 §22.2.2.2)。它将值格式化为 printf 打印的一样。与 %e 之一, %E, %f , %g , 或 %G格式说明符,取决于流的标志(表 58)。

同样,当输入 floatdouble值,它就像使用 scanf 一样读取它格式说明符为 %g 的函数(§22.2.2.1.2/5)。

那么,下一个问题是为什么 scanf无法正确解析 1.#QNAN . C89 标准在其对 fprintf 的描述中均未提及 NaN。和 fscanf功能。它确实说 float 的表示是未指定的,所以这属于未指定的行为。

另一方面,C99 确实在此处指定了行为。对于fprintf (C99 §7.19.6.1/8):

A double argument representing an infinity is converted in one of the styles [-]inf or [-]infinity — which style is implementation-defined. A double argument representing a NaN is converted in one of the styles [-]nan or [-]nan(<em>n-char-sequence</em>) — which style, and the meaning of any n-char-sequence, is implementation-defined. The F conversion specifier produces INF, INFINITY, or NAN instead of inf, infinity, or nan, respectively.243)

fscanf指定根据 strtod(3) 解析数(C99 §7.19.6.2/12)。 strtod解析如下(§7.20.1.3/3):

The expected form of the subject sequence is an optional plus or minus sign, then one of the following:
— a nonempty sequence of decimal digits optionally containing a decimal-point character, then an optional exponent part as defined in 6.4.4.2;
— a 0x or 0X, then a nonempty sequence of hexadecimal digits optionally containing a decimal-point character, then an optional binary exponent part as defined in 6.4.4.2;
INF or INFINITY, ignoring case
NAN or NAN(<em>n-char-sequence<sub>opt</sub></em>), ignoring case in the NAN part, where:

n-char-sequence:    digit    nondigit    n-char-sequence digit    n-char-sequence nondigit
The subject sequence is defined as the longest initial subsequence of the input string, starting with the first non-white-space character, that is of the expected form. The subject sequence contains no characters if the input string is not of the expected form.


因此,在考虑了所有这些之后,最终结果是您的 C 标准库不符合 C99,因为 1.#QNAN不是 fprintf 的有效输出根据上述。但是,众所周知,Microsoft 的 C 运行时不兼容 C99,据我所知,它不打算很快兼容。由于 C89 没有在此处指定与 NaN 相关的行为,因此您不走运。

您可以尝试切换到不同的编译器和 C 运行时(例如 Cygwin+GCC),但对于这么小的钉子来说,这是一个非常大的锤子。如果您真的需要这种行为,我建议您为 float 编写一个包装类,该类能够正确格式化和解析 NaN 值。

关于c++ - 使用 Visual C++ 的 NaN ASCII I/O,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7477978/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com