Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Examples

Simple example with std::stringstreams
locale old_locale;
locale tmp_locale(old_locale, new nonfinite_num_put<char>);
locale new_locale(tmp_locale, new nonfinite_num_get<char>);
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.
Use with lexical_cast
[Note] Note

From Boost 1.48, lexical_cast no longer uses stringstreams internally, and is now able to handle infinities and NaNs natively on most platforms.

Without using a new locale that contains the nonfinite facets, previous versions of lexical_cast using stringstream were not portable (and often failed) if nonfinite values are found.

locale old_locale;
locale tmp_locale(old_locale, new nonfinite_num_put<char>);
locale new_locale(tmp_locale, new nonfinite_num_get<char>);

Although other examples imbue individual streams with the new locale, for the streams constructed inside lexical_cast, it was necessary to assign to a global locale.

locale::global(new_locale);

lexical_cast then works as expected, even with infinity and NaNs.

double x = boost::lexical_cast<double>("inf");
assert(x == std::numeric:limits<double>::infinity());

string s = boost::lexical_cast<string>(numeric_limits<double>::infinity());
assert(s == "inf");
[Warning] Warning

If you use stringstream inside your functions, you may still need to use a global locale to handle nonfinites correctly. Or you need to imbue your stringstream with suitable get and put facets.

[Warning] Warning

You should be aware that the C++ specification does not explicitly require that input from decimal digits strings converts with rounding to the nearest representable floating-point binary value. (In contrast, decimal digits read by the compiler, for example by an assignment like double d = 1.234567890123456789, are guaranteed to assign the nearest representable value to double d). This implies that, no matter how many decimal digits you provide, there is a potential uncertainty of 1 least significant bit in the resulting binary value.

See conversion and rounding for more information on nearest representable and rounding and Exploring Binary for much detail on input and round-tripping difficulties.

Most iostream libraries do in fact achieve the desirable nearest representable floating-point binary value for all values of input. However one popular STL library does not quite achieve this for 64-bit doubles. See Decimal digit string input to double may be 1 bit wrong for the bizarre full details.

If you are expecting to 'round-trip' lexical_cast or serialization, for example archiving and loading, and want to be absolutely certain that you will always get an exactly identical double value binary pattern, you should use the suggested 'workaround' below that is believed to work on all platforms.

You should output using all potentially significant decimal digits, by setting stream precision to std::numeric_limits<double>::max_digits10, (or for the appropriate floating-point type, if not double) and crucially, require scientific format, not fixed or automatic (default), for example:

double output_value = any value;
std::stringstream s;
s << setprecison(std::numeric_limits<double>::max_digits10) << scientific << output_value;
s >> input_value;
Use with serialization archives

It is vital that the same locale is used when an archive is saved and when it is loaded. Otherwise, loading the archive may fail. By default, archives are saved and loaded with a classic C locale with a boost::archive::codecvt_null facet added. Normally you do not have to worry about that.

The constructors for the archive classes, as a side-effect, imbue the stream with such a locale. However, if you want to use the facets nonfinite_num_put and nonfinite_num_get with archives, then you have to manage the locale manually. That is done by calling the archive constructor with the flag boost::archive::no_codecvt, thereby ensuring that the archive constructor will not imbue the stream with a new locale.

The following code shows how to use nonfinite_num_put with a text_oarchive.

locale default_locale(locale::classic(), new boost::archive::codecvt_null<char>);
locale my_locale(default_locale, new nonfinite_num_put<char>);

ofstream ofs("test.txt");
ofs.imbue(my_locale);

boost::archive::text_oarchive oa(ofs, no_codecvt);

double x = numeric_limits<double>::infinity();
oa & x;

The same method works with nonfinite_num_get and text_iarchive.

If you use the nonfinite_num_put with trap_infinity and/or trap_nan flag with a serialization archive, then you must set the exception mask of the stream. Serialization archives do not check the stream state.

Other examples

nonfinite_facet_simple.cpp give some more simple demonstrations of the difference between using classic C locale and constructing a C99 infinity and NaN compliant locale for input and output.

See nonfinite_facet_sstream.cpp for this example of use with std::stringstreams.

For an example of how to enforce the MSVC 'legacy' "1.#INF" and "1.#QNAN" representations of infinity and NaNs, for input and output, see nonfinite_legacy.cpp.

Treatment of signaling NaN is demonstrated at ../../example/nonfinite_signaling_NaN.cpp

Example ../../example/nonfinite_loopback_ok.cpp shows loopback works OK.

Example ../../example/nonfinite_num_facet.cpp shows output and re-input of various finite and nonfinite values.

A simple example of trapping nonfinite output is at nonfinite_num_facet_trap.cpp.

A very basic example of using Boost.Archive is at ../../example/nonfinite_serialization_archives.cpp.

A full demonstration of serialization by Francois Mauger is at ../../example/nonfinite_num_facet_serialization.cpp


PrevUpHomeNext