boost/libs/multiprecision/doc/tutorial_io.qbk

120 lines
4.9 KiB
Plaintext
Raw Permalink Normal View History

2021-10-05 21:37:46 +02:00
[/
Copyright 2011 - 2020 John Maddock.
Copyright 2013 - 2019 Paul A. Bristow.
Copyright 2013 Christopher Kormanyos.
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).
]
[section:input_output Input Output]
[h4 Loopback testing]
['Loopback] or ['round-tripping] refers to writing out a value as a decimal digit string using `std::iostream`,
usually to a `std::stringstream`, and then reading the string back in to another value,
and confirming that the two values are identical. A trivial example using `float` is:
float write; // Value to round-trip.
std::stringstream ss; // Read and write std::stringstream.
ss.precision(std::numeric_limits<T>::max_digits10); // Ensure all potentially significant bits are output.
ss.flags(std::ios_base::fmtflags(std::ios_base::scientific)); // Use scientific format.
ss << write; // Output to string.
float read; // Expected.
ss >> read; // Read decimal digits string from stringstream.
BOOST_CHECK_EQUAL(write, read); // Should be the same.
and this can be run in a loop for all possible values of a 32-bit float.
For other floating-point types `T`, including __fundamental `double`,
it takes far too long to test all values,
so a reasonable test strategy is to use a large number of random values.
T write;
std::stringstream ss;
ss.precision(std::numeric_limits<T>::max_digits10); // Ensure all potentially significant bits are output.
ss.flags(f); // Changed from default iostream format flags if desired.
ss << write; // Output to stringstream.
T read;
ss >> read; // Get read using operator>> from stringstream.
BOOST_CHECK_EQUAL(read, write);
read = static_cast<T>(ss.str()); // Get read by converting from decimal digits string representation of write.
BOOST_CHECK_EQUAL(read, write);
read = static_cast<T>(write.str(0, f)); // Get read using format specified when written.
BOOST_CHECK_EQUAL(read, write);
The test at
[@../../test/test_cpp_bin_float_io.cpp test_cpp_bin_float_io.cpp]
allows any floating-point type to be ['round_tripped] using a wide range of fairly random values.
It also includes tests compared a collection of
[@../../test/string_data.ipp stringdata] test cases in a file.
[h4 Comparing with output using __fundamental types]
One can make some comparisons with the output of
<number<cpp_bin_float<53, digit_count_2> >
which has the same number of significant bits (53) as 64-bit double precision floating-point.
However, although most outputs are identical, there are differences on some platforms
caused by the implementation-dependent behaviours allowed by the C99 specification
[@http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf C99 ISO/IEC 9899:TC2],
incorporated by C++.
[:['"For e, E, f, F, g, and G conversions, if the number of significant decimal digits
is at most DECIMAL_DIG, then the result should be correctly rounded.
If the number of significant decimal digits is more than DECIMAL_DIG
but the source value is exactly representable with DECIMAL_DIG digits,
then the result should be an exact representation with trailing zeros.
Otherwise, the source value is bounded by two adjacent decimal strings L < U,
both having DECIMAL_DIG significant digits;
the value of the resultant decimal string D should satisfy L<= D <= U,
with the extra stipulation that the error should have a correct sign
for the current rounding direction."]]
So not only is correct rounding for the full number of digits not required,
but even if the *optional* recommended practice is followed,
then the value of these last few digits is unspecified
as long as the value is within certain bounds.
[note Do not expect the output from different platforms
to be [*identical], but `cpp_dec_float`, `cpp_bin_float` (and other backends) outputs should be
correctly rounded to the number of digits requested by the set precision and format.]
[h4 Macro BOOST_MP_MIN_EXPONENT_DIGITS]
[@http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf C99 Standard]
for [/e and E] format specifiers, 7.19.6 Formatted input/output functions requires:
\"The exponent always contains at least two digits,
and only as many more digits as necessary to represent the exponent.\"
So to conform to the C99 standard (incorporated by C++)
#define BOOST_MP_MIN_EXPONENT_DIGITS 2
Confusingly, Microsoft (and MinGW) do not conform to this standard and provide
[*at least three digits], for example `1e+001`.
So if you want the output to match that from
__fundamental floating-point types on compilers that use Microsofts runtime then use:
#define BOOST_MP_MIN_EXPONENT_DIGITS 3
Also useful to get the minimum exponent field width is
#define BOOST_MP_MIN_EXPONENT_DIGITS 1
producing a compact output like `2e+4`,
useful when conserving space is important.
Larger values are also supported, for example, value 4 for `2e+0004`
which may be useful to ensure that columns line up.
[endsect] [/section:input_output Input Output]