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
)
54 // Example of portable way to get `std::numeric_limits<T>::max_digits10`.
57 /*`For example, to be portable (including obselete platforms) for type `T` where `T` may be:
58 `float`, `double`, `long double`, `128-bit quad type`, `cpp_bin_float_50` ...
63 #if defined BOOST_NO_CXX11_NUMERIC_LIMITS
64 // No max_digits10 implemented.
65 std::cout
.precision(max_digits10
<T
>());
68 // Wrong value for std::numeric_limits<float>::max_digits10.
69 std::cout
.precision(max_digits10
<T
>());
70 #else // Use the C++11 max_digits10.
71 std::cout
.precision(std::numeric_limits
<T
>::max_digits10
);
75 std::cout
<< "std::cout.precision(max_digits10) = " << std::cout
.precision() << std::endl
; // 9
77 double x
= 1.2345678901234567889;
79 std::cout
<< "x = " << x
<< std::endl
; //
81 /*`which should output:
83 std::cout.precision(max_digits10) = 9
92 double write
= 2./3; // Any arbitrary value that cannot be represented exactly.
95 s
.precision(std::numeric_limits
<double>::digits10
); // or `float64_t` for 64-bit IEE754 double.
100 std::cout
<< std::setprecision(std::numeric_limits
<double>::digits10
)
101 << read
<< " != " << write
<< std::endl
;
104 //] [/max_digits10_2]
105 // 0.666666666666667 != 0.666666666666667
111 double pi
= boost::math::double_constants::pi
;
112 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
113 std::cout
<< pi
<< std::endl
; // 3.1415926535897931
115 //] [/max_digits10_3]
119 /*`and similarly for a much higher precision type:
122 using namespace boost::multiprecision
;
124 typedef number
<cpp_dec_float
<50> > cpp_dec_float_50
; // 50 decimal digits.
126 using boost::multiprecision::cpp_dec_float_50
;
128 cpp_dec_float_50 pi
= boost::math::constants::pi
<cpp_dec_float_50
>();
129 std::cout
.precision(std::numeric_limits
<cpp_dec_float_50
>::max_digits10
);
130 std::cout
<< pi
<< std::endl
;
131 // 3.141592653589793238462643383279502884197169399375105820974944592307816406
132 //] [/max_digits10_4]
138 for (int i
= 2; i
< 15; i
++)
140 std::cout
<< std::setw(std::numeric_limits
<int>::max_digits10
)
141 << boost::math::factorial
<double>(i
) << std::endl
;
144 //] [/max_digits10_5]
148 catch(std::exception ex
)
150 std::cout
<< "Caught Exception " << ex
.what() << std::endl
;
158 bool denorm
= std::numeric_limits
<T
>::denorm_min() < std::numeric_limits
<T
>::min();
159 BOOST_ASSERT(denorm
);
161 //] [/max_digits10_6]
165 unsigned char c
= 255;
166 std::cout
<< "char c = " << (int)c
<< std::endl
;
172 << std::setw(std::numeric_limits
<short>::digits10
+1 +1) // digits10+1, and +1 for sign.
173 << std::showpos
<< (std::numeric_limits
<short>::max
)() // +32767
175 << std::setw(std::numeric_limits
<short>::digits10
+1 +1)
176 << (std::numeric_limits
<short>::min
)() << std::endl
; // -32767
183 << std::setw(std::numeric_limits
<unsigned short>::digits10
+1 +1) // digits10+1, and +1 for sign.
184 << std::showpos
<< (std::numeric_limits
<unsigned short>::max
)() // 65535
186 << std::setw(std::numeric_limits
<unsigned short>::digits10
+1 +1) // digits10+1, and +1 for sign.
187 << (std::numeric_limits
<unsigned short>::min
)() << std::endl
; // 0
191 std::cout
<<std::noshowpos
<< std::endl
;
195 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
198 std::cout
<< d
<< "\n" << dp1
<< std::endl
;
201 std::cout
<< dp1
- d
<< std::endl
; // 1
207 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
210 std::cout
<< d
<< "\n" << dp1
<< std::endl
;
213 std::cout
<< dp1
- d
<< std::endl
; // 0 !!!
219 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
221 double eps
= std::numeric_limits
<double>::epsilon();
222 double dpeps
= d
+eps
;
223 std::cout
<< std::showpoint
// Ensure all trailing zeros are shown.
224 << d
<< "\n" // 1.0000000000000000
225 << dpeps
<< std::endl
; // 2.2204460492503131e-016
226 std::cout
<< dpeps
- d
// 1.0000000000000002
234 double nad
= boost::math::float_next(one
);
235 std::cout
<< nad
<< "\n" // 1.0000000000000002
236 << nad
- one
// 2.2204460492503131e-016
242 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
244 double eps
= std::numeric_limits
<double>::epsilon();
245 double dpeps
= d
+ eps
/2;
247 std::cout
<< std::showpoint
// Ensure all trailing zeros are shown.
248 << dpeps
<< "\n" // 1.0000000000000000
249 << eps
/2 << std::endl
; // 1.1102230246251565e-016
250 std::cout
<< dpeps
- d
// 0.00000000000000000
256 typedef double RealType
;
258 /*`A tolerance might be defined using this version of epsilon thus:
260 RealType tolerance
= boost::math::tools::epsilon
<RealType
>() * 2;
266 -(std::numeric_limits
<double>::max
)() == std::numeric_limits
<double>::lowest();
272 std::cout
.precision(std::numeric_limits
<double>::max_digits10
);
273 if (std::numeric_limits
<double>::has_denorm
== std::denorm_present
)
275 double d
= std::numeric_limits
<double>::denorm_min();
277 std::cout
<< d
<< std::endl
; // 4.9406564584124654e-324
281 double significand
= frexp(d
, &exponent
);
282 std::cout
<< "exponent = " << std::hex
<< exponent
<< std::endl
; // fffffbcf
283 std::cout
<< "significand = " << std::hex
<< significand
<< std::endl
; // 0.50000000000000000
287 std::cout
<< "No denormalization. " << std::endl
;
294 double round_err
= std::numeric_limits
<double>::epsilon() // 2.2204460492503131e-016
295 * std::numeric_limits
<double>::round_error(); // 1/2
296 std::cout
<< round_err
<< std::endl
; // 1.1102230246251565e-016
303 /*`For example, if we want a tolerance that might suit about 9 arithmetical operations,
304 say sqrt(9) = 3, we could define:
307 T tolerance
= 3 * std::numeric_limits
<T
>::epsilon();
309 /*`This is very widely used in Boost.Math testing
310 with Boost.Test's macro `BOOST_CHECK_CLOSE_FRACTION`
314 T calculated
= 1.0 + std::numeric_limits
<T
>::epsilon();
316 BOOST_CHECK_CLOSE_FRACTION(expected
, calculated
, tolerance
);
324 using boost::multiprecision::number
;
325 using boost::multiprecision::cpp_dec_float
;
326 using boost::multiprecision::et_off
;
328 typedef number
<cpp_dec_float
<50>, et_off
> cpp_dec_float_50
; // 50 decimal digits.
329 /*`[note that Boost.Test does not yet allow floating-point comparisons with expression templates on,
330 so the default expression template parameter has been replaced by `et_off`.]
333 cpp_dec_float_50 tolerance
= 3 * std::numeric_limits
<cpp_dec_float_50
>::epsilon();
334 cpp_dec_float_50 expected
= boost::math::constants::two_pi
<cpp_dec_float_50
>();
335 cpp_dec_float_50 calculated
= 2 * boost::math::constants::pi
<cpp_dec_float_50
>();
337 BOOST_CHECK_CLOSE_FRACTION(expected
, calculated
, tolerance
);
345 using boost::multiprecision::cpp_bin_float_quad
;
347 cpp_bin_float_quad tolerance
= 3 * std::numeric_limits
<cpp_bin_float_quad
>::epsilon();
348 cpp_bin_float_quad expected
= boost::math::constants::two_pi
<cpp_bin_float_quad
>();
349 cpp_bin_float_quad calculated
= 2 * boost::math::constants::pi
<cpp_bin_float_quad
>();
351 BOOST_CHECK_CLOSE_FRACTION(expected
, calculated
, tolerance
);
359 /*`NaN can be used with binary multiprecision types like `cpp_bin_float_quad`:
361 using boost::multiprecision::cpp_bin_float_quad
;
363 if (std::numeric_limits
<cpp_bin_float_quad
>::has_quiet_NaN
== true)
365 cpp_bin_float_quad tolerance
= 3 * std::numeric_limits
<cpp_bin_float_quad
>::epsilon();
367 cpp_bin_float_quad NaN
= std::numeric_limits
<cpp_bin_float_quad
>::quiet_NaN();
368 std::cout
<< "cpp_bin_float_quad NaN is " << NaN
<< std::endl
; // cpp_bin_float_quad NaN is nan
370 cpp_bin_float_quad expected
= NaN
;
371 cpp_bin_float_quad calculated
= 2 * NaN
;
372 // Comparisons of NaN's always fail:
373 bool b
= expected
== calculated
;
374 std::cout
<< b
<< std::endl
;
375 BOOST_CHECK_NE(expected
, expected
);
376 BOOST_CHECK_NE(expected
, calculated
);
380 std::cout
<< "Type " << typeid(cpp_bin_float_quad
).name() << " does not have NaNs!" << std::endl
;
390 See [@boost:/libs/math/example/nonfinite_facet_sstream.cpp]
393 #include <boost/math/special_functions/nonfinite_num_facets.hpp>
395 Then we can equally well use a multiprecision type cpp_bin_float_quad:
398 using boost::multiprecision::cpp_bin_float_quad
;
400 typedef cpp_bin_float_quad T
;
402 using boost::math::nonfinite_num_put
;
403 using boost::math::nonfinite_num_get
;
405 std::locale old_locale
;
406 std::locale
tmp_locale(old_locale
, new nonfinite_num_put
<char>);
407 std::locale
new_locale(tmp_locale
, new nonfinite_num_get
<char>);
408 std::stringstream ss
;
409 ss
.imbue(new_locale
);
410 T inf
= std::numeric_limits
<T
>::infinity();
411 ss
<< inf
; // Write out.
412 assert(ss
.str() == "inf");
414 ss
>> r
; // Read back in.
415 assert(inf
== r
); // Confirms that the floating-point values really are identical.
416 std::cout
<< "infinity output was " << ss
.str() << std::endl
;
417 std::cout
<< "infinity input was " << r
<< std::endl
;
421 infinity output was inf
422 infinity input was inf
424 Similarly we can do the same with NaN (except that we cannot use `assert`)
427 std::locale old_locale
;
428 std::locale
tmp_locale(old_locale
, new nonfinite_num_put
<char>);
429 std::locale
new_locale(tmp_locale
, new nonfinite_num_get
<char>);
430 std::stringstream ss
;
431 ss
.imbue(new_locale
);
433 T NaN
= std::numeric_limits
<T
>::quiet_NaN();
434 ss
<< NaN
; // Write out.
435 assert(ss
.str() == "nan");
436 std::cout
<< "NaN output was " << ss
.str() << std::endl
;
437 ss
>> n
; // Read back in.
438 std::cout
<< "NaN input was " << n
<< std::endl
;
449 } // BOOST_AUTO_TEST_CASE(test_numeric_limits_snips)