Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Introduction

The Problem

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 Solution

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] Tip

To add two facets, nonfinite_num_put and nonfinite_num_get, you may have to add one at a time, using a temporary locale.

Or you can create a new locale in one step

std::locale new_locale(std::locale(std::locale(std::locale(), new boost::math::nonfinite_num_put<char>), new boost::math::nonfinite_num_get<char>));

and, for example, use it to imbue an input and output stringstream.

[Tip] Tip

To just change an input or output stream, you can concisely write cout.imbue (std::locale(std::locale(), new boost::math::nonfinite_num_put<char>)); or cin.imbue (std::locale(std::locale(), new boost::math::nonfinite_num_get<char>));

stringstream ss;
ss.imbue(new_locale);
double inf = numeric_limits<double>::infinity();
ss << inf; // Write out.
BOOST_MATH_ASSERT(ss.str() == "inf");
double r;
ss >> r; // Read back in.
BOOST_MATH_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 standard for output of infinity and NaN

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.

C99 standard for output of infinity and NaN

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.

Signaling NaNs

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] 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] 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 float, double and long double have well-behaved signs.

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] Warning

This implementation does not (yet) provide output of, or access to, the NaN payload.


PrevUpHomeNext