...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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!
The facets nonfinite_num_put
and nonfinite_num_get
format
and parse all floating-point numbers, including infinity
and 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>);
Tip | |
---|---|
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. |
Tip | |
---|---|
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. BOOST_ASSERT(ss.str() == "inf"); double r; ss >> r; // Read back in. BOOST_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 2.1. C99 Representation of Infinity and NaN
number |
string |
---|---|
Positive infinity |
"inf" or "infinity" |
Positive NaN |
"nan" or "nan(...)" |
Negative infinity |
"-inf" or "-infinity" |
Negative NaN |
"-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
18.3.2.2 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
in C99
format, and output as 1.#QNAN
by Microsoft compilers.
Note | |
---|---|
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. |
Note | |
---|---|
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
types |
The numbers can be of type float
,
double
and long
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 by std::ios
manipulator uppercase
and lowercase
).
The function scanf
and similar
input functions are case-insensitive.
The dots in nan(...)
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:
Warning | |
---|---|
This implementation does not (yet) provide output of, or access to, the NaN payload. |