diff options
Diffstat (limited to 'libs/math/doc/sf_and_dist/fp_facets.qbk')
-rw-r--r-- | libs/math/doc/sf_and_dist/fp_facets.qbk | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/libs/math/doc/sf_and_dist/fp_facets.qbk b/libs/math/doc/sf_and_dist/fp_facets.qbk new file mode 100644 index 0000000000..0f285712c1 --- /dev/null +++ b/libs/math/doc/sf_and_dist/fp_facets.qbk @@ -0,0 +1,553 @@ +[section:fp_facets Facets for Floating-Point Infinities and NaNs] + +[import ../../example/nonfinite_facet_sstream.cpp] + +[h4 Synopsis] + + namespace boost{ namespace math + { + // Values for flags. + const int legacy; + const int signed_zero; + const int trap_infinity; + const int trap_nan; + + template< + class CharType, + class OutputIterator = std::ostreambuf_iterator<CharType> + > + class nonfinite_num_put : public std::num_put<CharType, OutputIterator> + { + public: + explicit nonfinite_num_put(int flags = 0); + }; + + template< + class CharType, + class InputIterator = std::istreambuf_iterator<CharType> + > + class nonfinite_num_get : public std::num_get<CharType, InputIterator> + { + public: + explicit nonfinite_num_get(int flags = 0); // legacy, sign_zero ... + }; + }} // namespace boost namespace math + +To use these facets + + #include <boost\math\special_functions\nonfinite_num_facets.hpp> + + +[section:intro Introduction] + +[h5 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! + +[h5 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. + +[nonfinite_facets_sstream_1] + +[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 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>));` +] + +[nonfinite_facets_sstream_2] + +[h4 C++0X standard for output of infinity and NaN] + +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf 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. + +[h4 C99 standard for output of infinity and NaN] + +The [@http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf 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 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. + +[h5 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 +[@http://en.wikipedia.org/wiki/IEEE_floating-point_standard IEEE 754-2008]. + +Floating-point values with layout ['s]111 1111 1['a]xx 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. +[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf 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 +[@http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf 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 `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 +[@http://publib.boulder.ibm.com/infocenter/zos/v1r10/index.jsp?topic=/com.ibm.zos.r10.bpxbd00/fprints.htm AIX NaN fprintf]. +That implementation specifies for Binary Floating Point NANs: + +* A NaN ordinal sequence is a left-parenthesis character '(', +followed by a digit sequence representing +an integer n, where 1 <= n <= INT_MAX-1, +followed by a right-parenthesis character ')'. + +* The integer value, n, is determined by the fraction bits of the NaN argument value as follows: + +* For a signalling NaN value, NaN fraction bits are reversed (left to right) +to produce bits (right to left) of an even integer value, 2*n. +Then formatted output functions produce a (signalling) NaN ordinal sequence +corresponding to the integer value n. + +* For a quiet NaN value, NaN fraction bits are reversed (left to right) +to produce bits (right to left) of an odd integer value, 2*n-1. +Then formatted output functions produce a (quiet) NaN ordinal sequence +corresponding to the integer value n. + +[warning This implementation does not (yet) provide output of, or access to, the NaN payload.] + +[endsect] [/section:intro Introduction] + +[section:reference Reference] + +[h5 The Facet `nonfinite_num_put`] + + template< + class CharType, class OutputIterator = std::ostreambuf_iterator<CharType> + > + class nonfinite_num_put; + +The `class nonfinite_num_put<CharType, OutputIterator>` +is derived from `std::num_put<CharType, OutputIterator>`. +Thus it is a facet that formats numbers. +The first template argument is the character type of the formatted strings, +usually `char` or `wchar_t`. +The second template argument is the type of iterator used to write the strings. +It is required to be an output iterator. +Usually the default `std::ostreambuf_iterator` is used. +The public interface of the class consists of a single constructor only: + + nonfinite_num_put(int flags = 0); + +The flags argument (effectively optional because a default of ` no_flags` is provided) +is discussed below. +The class template `nonfinite_num_put` is defined in the +header `boost/math/nonfinite_num_facets.hpp` +and lives in the namespace `boost::math`. + +Unlike the C++ Standard facet `std::num_put`, the facet `nonfinite_num_put` +formats `infinity` and `NaN` in a consistent and portable manner. +It uses the following string representations: + +[table +[[Number][String]] +[[Positive infinity][inf]] +[[Positive NaN][nan]] +[[Negative infinity][-inf]] +[[Negative NaN][-nan]] +] + +The numbers can be of type `float`, `double` and `long double`. +The strings can be in all lower case or all upper case. +An optional + sign can be used with positive numbers. +This can be controlled with the `uppercase`, `lowercase`, `showpos` and `noshowpos` manipulators. +Formatting of integers, boolean values and finite floating-point numbers is simply delegated to the normal `std::num_put`. + + +[h5 Facet `nonfinite_num_get`] + + template<class CharType, class InputIterator = std::istreambuf_iterator<CharType> > class nonfinite_num_get; + +The class `nonfinite_num_get<CharType, InputIterator>` is derived from `std::num_get<CharType, IntputIterator>`. +Thus it is a facet that parses strings that represent numbers. +The first template argument is the character type of the strings, +usually `char` or `wchar_t`. +The second template argument is the type of iterator used to read the strings. +It is required to be an input iterator. Usually the default is used. +The public interface of the class consists of a single constructor only: + + nonfinite_num_get(int flags = 0); + +The flags argument is discussed below. +The `class template nonfinite_num_get` is defined +in the header `boost/math/nonfinite_num_facets.hpp` +and lives in the `namespace boost::math`. + +Unlike the facet `std::num_get`, the facet `nonfinite_num_get` parses strings +that represent `infinity` and `NaN` in a consistent and portable manner. +It recognizes precisely the string representations specified by the C99 standard: + +[table +[[Number][String]] +[[Positive infinity][inf, infinity]] +[[Positive NaN][nan, nan(...)]] +[[Negative infinity][-inf, -infinity]] +[[Negative NaN][-nan, -nan(...)]] +] + +The numbers can be of type `float`, `double` and `long double`. +The facet is case-insensitive. An optional + sign can be used with positive numbers. +The dots in nan(...) stand for an arbitrary string usually containing the ['NaN payload]. +Parsing of strings that represent integers, boolean values +and finite floating-point numbers is delegated to `std::num_get`. + +When the facet parses a string that represents `infinity` on a platform that lacks infinity, +then the fail bit of the stream is set. + +When the facet parses a string that represents `NaN` on a platform that lacks NaN, +then the fail bit of the stream is set. + +[h4 Flags] + +The constructors for `nonfinite_num_put` and `nonfinite_num_get` +take an optional bit flags argument. +There are four different bit flags: + +* legacy +* signed_zero +* trap_infinity +* trap_nan + +The flags can be combined with the OR `operator|`. + +The flags are defined in the header `boost/math/nonfinite_num_facets.hpp` +and live in the `namespace boost::math`. + +[h5 legacy] + +The legacy flag has no effect with the output facet `nonfinite_num_put`. + +If the legacy flag is used with the `nonfinite_num_get` input facet, +then the facet will recognize all the following string representations of `infinity` and `NaN`: + +[table +[[Number][String]] +[[Positive infinity][inf, infinity, one#inf]] +[[Positive NaN][nan, nan(...), nanq, nans, qnan, snan, one#ind, one#qnan, one#snan]] +[[Negative infinity][-inf, -infinity, -one#inf]] +[[Negative NaN][-nan, -nan(...), -nanq, -nans, -qnan, -snan, -one#ind, - one#qnan, -one#snan]] +] + +* The numbers can be of type `float`, `double` and `long double`. +* The facet is case-insensitive. +* An optional `+` sign can be used with the positive values. +* The dots in `nan(...)` stand for an arbitrary string. +* `one` stands for any string that `std::num_get` parses as the number `1`, +typically "1.#INF", "1.QNAN" but also "000001.#INF"... + +The list includes a number of non-standard string representations of infinity and NaN +that are used by various existing implementations of the C++ standard library, +and also string representations used by other programming languages. + +[h5 signed_zero] + +If the `signed_zero` flag is used with `nonfinite_num_put`, +then the facet will distinguish between positive and negative zero. +It will format positive zero as "0" or "+0" and negative zero as "-0". +The string representation of positive zero can be controlled +with the `showpos` and `noshowpos` manipulators. + +The `signed_zero flag` has no effect with the input facet `nonfinite_num_get`. +The input facet `nonfinite_num_get` always parses "0" and "+0" +as positive zero and "-0" as negative zero, +as do most implementations of `std::num_get`. + +[h5 trap_infinity] + +If the `trap_infinity` flag is used with `nonfinite_num_put`, +then the facet will throw an exception of type `std::ios_base::failure` +when an attempt is made to format positive or negative infinity. +If the facet is called from a stream insertion operator, +then the stream will catch that exception and set either its `fail bit` or its `bad bit`. +Which bit is set is platform dependent. + +If the `trap_infinity` flag is used with `nonfinite_num_get`, +then the facet will set the `fail bit` of the stream when an attempt is made +to parse a string that represents positive or negative infinity. + +(See Design Rationale below for a discussion of this inconsistency.) + +[h5 trap_nan] + +Same as `trap_infinity`, but positive and negative NaN are trapped instead. + +[endsect] [/section:reference Reference] + + +[section:examples Examples] + +[h5 Simple example with std::stringstreams] + +[nonfinite_facets_sstream_1] +[nonfinite_facets_sstream_2] + +[h5 Use with lexical_cast] + +[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. + +[nonfinite_facets_sstream_1] + +Although other examples imbue individual streams with the new locale, +for the streams constructed inside lexical_cast, +it was necesary 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 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 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 [@http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding +for more information on ['nearest representable] and ['rounding]]. + +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 +[@http://connect.microsoft.com/VisualStudio/feedback/details/98770/decimal-digit-string-input-to-double-may-be-1-bit-wrong +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; + + +[h4 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. + + +[h5 Other examples] + +[@../../../example/nonfinite_facet_simple.cpp nonfinite_facet_simple.cpp] +give some more simple demonstrations of the difference between using classic C locale +and constructing a C99 infinty and NaN compliant locale for input and output. + +See [@../../../example/nonfinite_facet_sstream.cpp nonfinite_facet_sstream.cpp] +for this example of use with `std::stringstream`s. + +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 [@../../../example/nonfinite_legacy.cpp 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 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] + +[endsect] [/section:examples Examples] + +[section:portability Portability] + +This library uses the floating-point number classification and sign-bit from Boost.Math library, +and should work on all platforms where that library works. +See the portability information for that library. + +[endsect] [/section:portability Portability] + +[section:rationale Design Rationale] + +* The flags are implemented as a const data member of the facet. +Facets are reference counted, and locales can share facets. +Therefore changing the flags of a facet would have effects that are hard to predict. +An alternative design would be to implement the flags +using `std::ios_base::xalloc` and `std::ios_base::iword`. +Then one could safely modify the flags, and one could define manipulators that do so. +However, for that to work with dynamically linked libraries, +a `.cpp` file would have to be added to the library. +It was judged be more desirable to have a headers only library, +than to have mutable flags and manipulators. + +* The facet `nonfinite_num_put` throws an exception when +the `trap_infinity` or `trap_nan` flag is set +and an attempt is made to format infinity or NaN. +It would be better if the facet set the fail bit of the stream. +However, facets derived from `std::num_put` do not have access to the stream state. + +[endsect] [/section:rationale Design Rationale] + +[endsect] [/section:fp_facets Facets for Floating-Point Infinities and NaNs] + +[/ + Copyright Johan Rade and Paul A. Bristow 2011. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +] + + + + |