...one of the most highly
regarded and expertly designed C++ library projects in the
world. — Herb Sutter and Andrei
The C++98 standard does not specify how infinity and NaN are represented in text streams. As a result, different platforms use different string representations. This can cause undefined behavior when text files are moved between different platforms. Some platforms cannot even input parse their own output! So 'route-tripping' or loopback of output to input is not possible. For instance, the following test fails with MSVC:
stringstream ss; double inf = numeric_limits<double>::infinity(); double r; ss << inf; // Write out. ss >> r; // Read back in. cout << "infinity output was " << inf << endl; // 1.#INF cout << "infinity input was " << r << endl; // 1 assert(inf == y); // Fails!
and parse all floating-point numbers, including
NaN, in a consistent
and portable manner.
The following test succeeds with MSVC.
locale old_locale; locale tmp_locale(old_locale, new nonfinite_num_put<char>); locale new_locale(tmp_locale, new nonfinite_num_get<char>);
To add two facets,
Or you can create a new locale in one step
and, for example, use it to imbue an input and output stringstream.
To just change an input or output stream, you can concisely write
stringstream ss; ss.imbue(new_locale); double inf = numeric_limits<double>::infinity(); ss << inf; // Write out. assert(ss.str() == "inf"); double r; ss >> r; // Read back in. assert(inf == r); // Confirms that the double values really are identical. cout << "infinity output was " << ss.str() << endl; cout << "infinity input was " << r << endl; // But the string representation of r displayed will be the native type // because, when it was constructed, cout had NOT been imbued // with the new locale containing the nonfinite_numput facet. // So the cout output will be "1.#INF on MS platforms // and may be "inf" or other string representation on other platforms.
C++0X (final) draft standard does not explicitly specify the representation (and input) of nonfinite values, leaving it implementation-defined. So without some specific action, input and output of nonfinite values is not portable.
The C99 standard does specify how infinity and NaN are formatted by printf and similar output functions, and parsed by scanf and similar input functions.
The following string representations are used:
Table 51. C99 Representation of Infinity and NaN
"inf" or "infinity"
"nan" or "nan(...)"
"-inf" or "-infinity"
"-nan" or "-nan(...)"
So following C99 provides a sensible 'standard' way of handling input and output of nonfinites in C++, and this implementation follows most of these formats.
A particular type of NaN is the signaling NaN. The usual mechanism of signaling is by raising a floating-point exception. Signaling NaNs are defined by IEEE 754-2008.
Floating-point values with layout s111 1111 1axx xxxx xxxx xxxx xxxx xxxx where s is the sign, x is the payload, and bit a determines the type of NaN.
If bit a = 1, it is a quiet NaN.
If bit a is zero and the payload x is nonzero, then it is a signaling NaN.
Although there has been theoretical interest in the ability of a signaling
NaN to raise an exception, for example to prevent use of an uninitialised
variable, in practice there appears to be no useful application of signaling
NaNs for most current processors. C++0X
220.127.116.11 still specifies a (implementation-defined) representation
for signaling NaN, and
static constexpr bool
has_signaling_NaN a method of
checking if a floating-point type has a representation for signaling NaN.
But in practice, most platforms treat signaling NaNs in the same as quiet
NaNs. So, for example, they are represented by "nan" on output
format, and output as
by Microsoft compilers.
The C99 standard does not distinguish between the quiet NaN and signaling NaN values. A quiet NaN propagates through almost every arithmetic operation without raising a floating-point exception; a signaling NaN generally raises a floating-point exception when occurring as an arithmetic operand.
C99 specification does not define the behavior of signaling NaNs. NaNs created by IEC 60559 operations are always quiet. Therefore this implementation follows C99, and treats the signaling NaN bit as just a part of the NaN payload field. So this implementation does not distinguish between the two classes of NaN.
An implementation may give zero and non-numeric values (such as infinities and NaNs) a sign or may leave them unsigned. Wherever such values are unsigned, any requirement in the C99 Standard to retrieve the sign shall produce an unspecified sign, and any requirement to set the sign shall be ignored.
This might apply to user-defined types, but in practice built-in floating-point
The numbers can be of type
double. An optional + sign can be
used with positive numbers (controlled by ios manipulator
showpos). The function
printf and similar C++ functions use
standard formatting flags to put all lower or all upper case (controlled
similar input functions are case-insensitive.
The dots in
stand for an arbitrary string. The meaning of that string is implementation
dependent. It can be used to convey extra information about the NaN, from
the 'payload'. A particular value of the payload might be used to indicate
a missing value, for example.
This library uses the string representations specified by the C99 standard.
An example of an implementation that optionally includes the NaN payload information is at AIX NaN fprintf. That implementation specifies for Binary Floating Point NANs:
This implementation does not (yet) provide output of, or access to, the NaN payload.