1 // Copyright Paul A. Bristow 2013
2 // Copyright John Maddock 2013
3 // Copyright Christopher Kormanyos
5 // Use, modification and distribution are subject to the
6 // Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE_1_0.txt
8 // or copy at http://www.boost.org/LICENSE_1_0.txt)
10 // Examples of numeric_limits usage as snippets for multiprecision documentation.
12 // Includes text as Quickbook comments.
18 #include <limits> // numeric_limits
21 #include <boost/assert.hpp>
23 #include <boost/math/constants/constants.hpp>
24 #include <boost/math/special_functions/nonfinite_num_facets.hpp>
26 #include <boost/math/special_functions/factorials.hpp>
27 #include <boost/math/special_functions/next.hpp>
28 #include <boost/math/tools/precision.hpp>
29 #include <boost/multiprecision/cpp_dec_float.hpp> // is decimal.
30 #include <boost/multiprecision/cpp_bin_float.hpp> // is binary.
32 #define BOOST_TEST_MAIN
33 #include <boost/test/unit_test.hpp> // Boost.Test
34 #include <boost/test/floating_point_comparison.hpp>
36 static long double const log10Two
= 0.30102999566398119521373889472449L; // log10(2.)
41 int significand_digits
= std::numeric_limits
<T
>::digits
;
42 // BOOST_CONSTEXPR_OR_CONST int significand_digits = std::numeric_limits<T>::digits;
43 return static_cast<int>(ceil(1 + significand_digits
* log10Two
));
44 } // template <typename T> int max_digits10()
46 // Used to test max_digits10<>() function below.
47 //#define BOOST_NO_CXX11_NUMERIC_LIMITS
49 BOOST_AUTO_TEST_CASE(test_numeric_limits_snips
)
51 #if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(BOOST_MSVC) && (BOOST_MSVC == 1600))
55 // Example of portable way to get `std::numeric_limits<T>::max_digits10`.
58 /*`For example, to be portable (including obselete platforms) for type `T` where `T` may be:
59 `float`, `double`, `long double`, `128-bit quad type`, `cpp_bin_float_50` ...
64 #if defined BOOST_NO_CXX11_NUMERIC_LIMITS
65 // No max_digits10 implemented.
66 std::cout
.precision(max_digits10
<T
>());
69 // Wrong value for std::numeric_limits<float>::max_digits10.
70 std::cout
.precision(max_digits10
<T
>());
71 #else // Use the C++11 max_digits10.
72 std::cout
.precision(std::numeric_limits
<T
>::max_digits10
);
76 std::cout
<< "std::cout.precision(max_digits10) = " << std::cout
.precision() << std::endl
; // 9
78 double x
= 1.2345678901234567889;
80 std::cout
<< "x = " << x
<< std::endl
; //
82 /*`which should output:
84 std::cout.precision(max_digits10) = 9
93 double write
= 2./3; // Any arbitrary value that cannot be represented exactly.
96 s
.precision(std::numeric_limits
<double>::digits10
); // or `float64_t` for 64-bit IEE754 double.
101 std::cout
<< std::setprecision(std::numeric_limits
<double>::digits10
)
102 << read
<< " != " << write
<< std::endl
;
105 //] [/max_digits10_2]
106 // 0.666666666666667 != 0.666666666666667
112 double pi
= boost::math::double_constants::pi
;
113 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
114 std::cout
<< pi
<< std::endl
; // 3.1415926535897931
116 //] [/max_digits10_3]
120 /*`and similarly for a much higher precision type:
123 using namespace boost::multiprecision
;
125 typedef number
<cpp_dec_float
<50> > cpp_dec_float_50
; // 50 decimal digits.
127 using boost::multiprecision::cpp_dec_float_50
;
129 cpp_dec_float_50 pi
= boost::math::constants::pi
<cpp_dec_float_50
>();
130 std::cout
.precision(std::numeric_limits
<cpp_dec_float_50
>::max_digits10
);
131 std::cout
<< pi
<< std::endl
;
132 // 3.141592653589793238462643383279502884197169399375105820974944592307816406
133 //] [/max_digits10_4]
139 for (int i
= 2; i
< 15; i
++)
141 std::cout
<< std::setw(std::numeric_limits
<int>::max_digits10
)
142 << boost::math::factorial
<double>(i
) << std::endl
;
145 //] [/max_digits10_5]
149 catch(std::exception ex
)
151 std::cout
<< "Caught Exception " << ex
.what() << std::endl
;
159 bool denorm
= std::numeric_limits
<T
>::denorm_min() < (std::numeric_limits
<T
>::min
)();
160 BOOST_ASSERT(denorm
);
162 //] [/max_digits10_6]
166 unsigned char c
= 255;
167 std::cout
<< "char c = " << (int)c
<< std::endl
;
173 << std::setw(std::numeric_limits
<short>::digits10
+1 +1) // digits10+1, and +1 for sign.
174 << std::showpos
<< (std::numeric_limits
<short>::max
)() // +32767
176 << std::setw(std::numeric_limits
<short>::digits10
+1 +1)
177 << (std::numeric_limits
<short>::min
)() << std::endl
; // -32767
184 << std::setw(std::numeric_limits
<unsigned short>::digits10
+1 +1) // digits10+1, and +1 for sign.
185 << std::showpos
<< (std::numeric_limits
<unsigned short>::max
)() // 65535
187 << std::setw(std::numeric_limits
<unsigned short>::digits10
+1 +1) // digits10+1, and +1 for sign.
188 << (std::numeric_limits
<unsigned short>::min
)() << std::endl
; // 0
192 std::cout
<<std::noshowpos
<< std::endl
;
196 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
199 std::cout
<< d
<< "\n" << dp1
<< std::endl
;
202 std::cout
<< dp1
- d
<< std::endl
; // 1
208 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
211 std::cout
<< d
<< "\n" << dp1
<< std::endl
;
214 std::cout
<< dp1
- d
<< std::endl
; // 0 !!!
220 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
222 double eps
= std::numeric_limits
<double>::epsilon();
223 double dpeps
= d
+eps
;
224 std::cout
<< std::showpoint
// Ensure all trailing zeros are shown.
225 << d
<< "\n" // 1.0000000000000000
226 << dpeps
<< std::endl
; // 2.2204460492503131e-016
227 std::cout
<< dpeps
- d
// 1.0000000000000002
235 double nad
= boost::math::float_next(one
);
236 std::cout
<< nad
<< "\n" // 1.0000000000000002
237 << nad
- one
// 2.2204460492503131e-016
243 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
245 double eps
= std::numeric_limits
<double>::epsilon();
246 double dpeps
= d
+ eps
/2;
248 std::cout
<< std::showpoint
// Ensure all trailing zeros are shown.
249 << dpeps
<< "\n" // 1.0000000000000000
250 << eps
/2 << std::endl
; // 1.1102230246251565e-016
251 std::cout
<< dpeps
- d
// 0.00000000000000000
257 typedef double RealType
;
259 /*`A tolerance might be defined using this version of epsilon thus:
261 RealType tolerance
= boost::math::tools::epsilon
<RealType
>() * 2;
267 -(std::numeric_limits
<double>::max
)() == std::numeric_limits
<double>::lowest();
269 // warning C4553: '==': result of expression not used; did you intend '='? is spurious.
274 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
275 if (std::numeric_limits
<double>::has_denorm
== std::denorm_present
)
277 double d
= std::numeric_limits
<double>::denorm_min();
279 std::cout
<< d
<< std::endl
; // 4.9406564584124654e-324
283 double significand
= frexp(d
, &exponent
);
284 std::cout
<< "exponent = " << std::hex
<< exponent
<< std::endl
; // fffffbcf
285 std::cout
<< "significand = " << std::hex
<< significand
<< std::endl
; // 0.50000000000000000
289 std::cout
<< "No denormalization. " << std::endl
;
296 double round_err
= std::numeric_limits
<double>::epsilon() // 2.2204460492503131e-016
297 * std::numeric_limits
<double>::round_error(); // 1/2
298 std::cout
<< round_err
<< std::endl
; // 1.1102230246251565e-016
305 /*`For example, if we want a tolerance that might suit about 9 arithmetical operations,
306 say sqrt(9) = 3, we could define:
309 T tolerance
= 3 * std::numeric_limits
<T
>::epsilon();
311 /*`This is very widely used in Boost.Math testing
312 with Boost.Test's macro `BOOST_CHECK_CLOSE_FRACTION`
316 T calculated
= 1.0 + std::numeric_limits
<T
>::epsilon();
318 BOOST_CHECK_CLOSE_FRACTION(expected
, calculated
, tolerance
);
323 #if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32))
327 using boost::multiprecision::number
;
328 using boost::multiprecision::cpp_dec_float
;
329 using boost::multiprecision::et_off
;
331 typedef number
<cpp_dec_float
<50>, et_off
> cpp_dec_float_50
; // 50 decimal digits.
332 /*`[note that Boost.Test does not yet allow floating-point comparisons with expression templates on,
333 so the default expression template parameter has been replaced by `et_off`.]
336 cpp_dec_float_50 tolerance
= 3 * std::numeric_limits
<cpp_dec_float_50
>::epsilon();
337 cpp_dec_float_50 expected
= boost::math::constants::two_pi
<cpp_dec_float_50
>();
338 cpp_dec_float_50 calculated
= 2 * boost::math::constants::pi
<cpp_dec_float_50
>();
340 BOOST_CHECK_CLOSE_FRACTION(expected
, calculated
, tolerance
);
348 using boost::multiprecision::cpp_bin_float_quad
;
350 cpp_bin_float_quad tolerance
= 3 * std::numeric_limits
<cpp_bin_float_quad
>::epsilon();
351 cpp_bin_float_quad expected
= boost::math::constants::two_pi
<cpp_bin_float_quad
>();
352 cpp_bin_float_quad calculated
= 2 * boost::math::constants::pi
<cpp_bin_float_quad
>();
354 BOOST_CHECK_CLOSE_FRACTION(expected
, calculated
, tolerance
);
362 using boost::multiprecision::cpp_bin_float_oct
;
364 cpp_bin_float_oct tolerance
= 3 * std::numeric_limits
<cpp_bin_float_oct
>::epsilon();
365 cpp_bin_float_oct expected
= boost::math::constants::two_pi
<cpp_bin_float_oct
>();
366 cpp_bin_float_oct calculated
= 2 * boost::math::constants::pi
<cpp_bin_float_oct
>();
368 BOOST_CHECK_CLOSE_FRACTION(expected
, calculated
, tolerance
);
376 /*`NaN can be used with binary multiprecision types like `cpp_bin_float_quad`:
378 using boost::multiprecision::cpp_bin_float_quad
;
380 if (std::numeric_limits
<cpp_bin_float_quad
>::has_quiet_NaN
== true)
382 cpp_bin_float_quad tolerance
= 3 * std::numeric_limits
<cpp_bin_float_quad
>::epsilon();
384 cpp_bin_float_quad NaN
= std::numeric_limits
<cpp_bin_float_quad
>::quiet_NaN();
385 std::cout
<< "cpp_bin_float_quad NaN is " << NaN
<< std::endl
; // cpp_bin_float_quad NaN is nan
387 cpp_bin_float_quad expected
= NaN
;
388 cpp_bin_float_quad calculated
= 2 * NaN
;
389 // Comparisons of NaN's always fail:
390 bool b
= expected
== calculated
;
391 std::cout
<< b
<< std::endl
;
392 BOOST_CHECK_NE(expected
, expected
);
393 BOOST_CHECK_NE(expected
, calculated
);
397 std::cout
<< "Type " << typeid(cpp_bin_float_quad
).name() << " does not have NaNs!" << std::endl
;
407 See [@boost:/libs/math/example/nonfinite_facet_sstream.cpp]
410 #include <boost/math/special_functions/nonfinite_num_facets.hpp>
412 Then we can equally well use a multiprecision type cpp_bin_float_quad:
415 using boost::multiprecision::cpp_bin_float_quad
;
417 typedef cpp_bin_float_quad T
;
419 using boost::math::nonfinite_num_put
;
420 using boost::math::nonfinite_num_get
;
422 std::locale old_locale
;
423 std::locale
tmp_locale(old_locale
, new nonfinite_num_put
<char>);
424 std::locale
new_locale(tmp_locale
, new nonfinite_num_get
<char>);
425 std::stringstream ss
;
426 ss
.imbue(new_locale
);
427 T inf
= std::numeric_limits
<T
>::infinity();
428 ss
<< inf
; // Write out.
429 BOOST_ASSERT(ss
.str() == "inf");
431 ss
>> r
; // Read back in.
432 BOOST_ASSERT(inf
== r
); // Confirms that the floating-point values really are identical.
433 std::cout
<< "infinity output was " << ss
.str() << std::endl
;
434 std::cout
<< "infinity input was " << r
<< std::endl
;
439 infinity output was inf
440 infinity input was inf
442 Similarly we can do the same with NaN (except that we cannot use `assert` (because any comparisons with NaN always return false).
445 std::locale old_locale
;
446 std::locale
tmp_locale(old_locale
, new nonfinite_num_put
<char>);
447 std::locale
new_locale(tmp_locale
, new nonfinite_num_get
<char>);
448 std::stringstream ss
;
449 ss
.imbue(new_locale
);
451 T NaN
= std::numeric_limits
<T
>::quiet_NaN();
452 ss
<< NaN
; // Write out.
453 BOOST_ASSERT(ss
.str() == "nan");
454 std::cout
<< "NaN output was " << ss
.str() << std::endl
;
455 ss
>> n
; // Read back in.
456 std::cout
<< "NaN input was " << n
<< std::endl
;
469 } // BOOST_AUTO_TEST_CASE(test_numeric_limits_snips)