]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright Paul A. Bristow 2013 |
2 | // Copyright John Maddock 2013 | |
3 | // Copyright Christopher Kormanyos | |
4 | ||
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) | |
9 | ||
10 | // Examples of numeric_limits usage as snippets for multiprecision documentation. | |
11 | ||
12 | // Includes text as Quickbook comments. | |
13 | ||
14 | #include <iostream> | |
15 | #include <iomanip> | |
16 | #include <string> | |
17 | #include <sstream> | |
18 | #include <limits> // numeric_limits | |
19 | #include <iomanip> | |
20 | #include <locale> | |
21 | #include <boost/assert.hpp> | |
22 | ||
23 | #include <boost/math/constants/constants.hpp> | |
24 | #include <boost/math/special_functions/nonfinite_num_facets.hpp> | |
25 | ||
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. | |
31 | ||
32 | #define BOOST_TEST_MAIN | |
33 | #include <boost/test/unit_test.hpp> // Boost.Test | |
34 | #include <boost/test/floating_point_comparison.hpp> | |
35 | ||
36 | static long double const log10Two = 0.30102999566398119521373889472449L; // log10(2.) | |
37 | ||
38 | template <typename T> | |
39 | int max_digits10() | |
40 | { | |
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() | |
45 | ||
46 | // Used to test max_digits10<>() function below. | |
47 | //#define BOOST_NO_CXX11_NUMERIC_LIMITS | |
48 | ||
49 | BOOST_AUTO_TEST_CASE(test_numeric_limits_snips) | |
50 | { | |
b32b8144 | 51 | #if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(BOOST_MSVC) && (BOOST_MSVC == 1600)) |
7c673cae FG |
52 | try |
53 | { | |
54 | ||
55 | // Example of portable way to get `std::numeric_limits<T>::max_digits10`. | |
56 | //[max_digits10_1 | |
57 | ||
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` ... | |
60 | */ | |
61 | ||
62 | typedef float T; | |
63 | ||
64 | #if defined BOOST_NO_CXX11_NUMERIC_LIMITS | |
65 | // No max_digits10 implemented. | |
66 | std::cout.precision(max_digits10<T>()); | |
67 | #else | |
68 | #if(_MSC_VER <= 1600) | |
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); | |
73 | #endif | |
74 | #endif | |
75 | ||
76 | std::cout << "std::cout.precision(max_digits10) = " << std::cout.precision() << std::endl; // 9 | |
77 | ||
78 | double x = 1.2345678901234567889; | |
79 | ||
80 | std::cout << "x = " << x << std::endl; // | |
81 | ||
82 | /*`which should output: | |
83 | ||
84 | std::cout.precision(max_digits10) = 9 | |
85 | x = 1.23456789 | |
86 | */ | |
87 | ||
88 | //] [/max_digits10_1] | |
89 | ||
90 | { | |
91 | //[max_digits10_2 | |
92 | ||
93 | double write = 2./3; // Any arbitrary value that cannot be represented exactly. | |
94 | double read = 0; | |
95 | std::stringstream s; | |
96 | s.precision(std::numeric_limits<double>::digits10); // or `float64_t` for 64-bit IEE754 double. | |
97 | s << write; | |
98 | s >> read; | |
99 | if(read != write) | |
100 | { | |
101 | std::cout << std::setprecision(std::numeric_limits<double>::digits10) | |
102 | << read << " != " << write << std::endl; | |
103 | } | |
104 | ||
105 | //] [/max_digits10_2] | |
106 | // 0.666666666666667 != 0.666666666666667 | |
107 | } | |
108 | ||
109 | { | |
110 | //[max_digits10_3 | |
111 | ||
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 | |
115 | ||
116 | //] [/max_digits10_3] | |
117 | } | |
118 | { | |
119 | //[max_digits10_4 | |
120 | /*`and similarly for a much higher precision type: | |
121 | */ | |
122 | ||
123 | using namespace boost::multiprecision; | |
124 | ||
125 | typedef number<cpp_dec_float<50> > cpp_dec_float_50; // 50 decimal digits. | |
126 | ||
127 | using boost::multiprecision::cpp_dec_float_50; | |
128 | ||
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] | |
134 | } | |
135 | ||
136 | { | |
137 | //[max_digits10_5 | |
138 | ||
139 | for (int i = 2; i < 15; i++) | |
140 | { | |
141 | std::cout << std::setw(std::numeric_limits<int>::max_digits10) | |
142 | << boost::math::factorial<double>(i) << std::endl; | |
143 | } | |
144 | ||
145 | //] [/max_digits10_5] | |
146 | } | |
147 | ||
148 | } | |
149 | catch(std::exception ex) | |
150 | { | |
151 | std::cout << "Caught Exception " << ex.what() << std::endl; | |
152 | } | |
153 | ||
154 | { | |
155 | //[max_digits10_6 | |
156 | ||
157 | typedef double T; | |
158 | ||
159 | bool denorm = std::numeric_limits<T>::denorm_min() < std::numeric_limits<T>::min(); | |
160 | BOOST_ASSERT(denorm); | |
161 | ||
162 | //] [/max_digits10_6] | |
163 | } | |
164 | ||
165 | { | |
166 | unsigned char c = 255; | |
167 | std::cout << "char c = " << (int)c << std::endl; | |
168 | } | |
169 | ||
170 | { | |
171 | //[digits10_1 | |
172 | std::cout | |
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 | |
175 | << std::endl | |
176 | << std::setw(std::numeric_limits<short>::digits10 +1 +1) | |
177 | << (std::numeric_limits<short>::min)() << std::endl; // -32767 | |
178 | //] [/digits10_1] | |
179 | } | |
180 | ||
181 | { | |
182 | //[digits10_2 | |
183 | std::cout | |
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 | |
186 | << std::endl | |
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 | |
189 | //] [/digits10_2] | |
190 | } | |
191 | ||
192 | std::cout <<std::noshowpos << std::endl; | |
193 | ||
194 | { | |
195 | //[digits10_3 | |
196 | std::cout.precision(std::numeric_limits<double>::max_digits10); | |
197 | double d = 1e15; | |
198 | double dp1 = d+1; | |
199 | std::cout << d << "\n" << dp1 << std::endl; | |
200 | // 1000000000000000 | |
201 | // 1000000000000001 | |
202 | std::cout << dp1 - d << std::endl; // 1 | |
203 | //] [/digits10_3] | |
204 | } | |
205 | ||
206 | { | |
207 | //[digits10_4 | |
208 | std::cout.precision(std::numeric_limits<double>::max_digits10); | |
209 | double d = 1e16; | |
210 | double dp1 = d+1; | |
211 | std::cout << d << "\n" << dp1 << std::endl; | |
212 | // 10000000000000000 | |
213 | // 10000000000000000 | |
214 | std::cout << dp1 - d << std::endl; // 0 !!! | |
215 | //] [/digits10_4] | |
216 | } | |
217 | ||
218 | { | |
219 | //[epsilon_1 | |
220 | std::cout.precision(std::numeric_limits<double>::max_digits10); | |
221 | double d = 1.; | |
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 | |
228 | << std::endl; | |
229 | //] [epsilon_1] | |
230 | } | |
231 | ||
232 | { | |
233 | //[epsilon_2 | |
234 | double one = 1.; | |
235 | double nad = boost::math::float_next(one); | |
236 | std::cout << nad << "\n" // 1.0000000000000002 | |
237 | << nad - one // 2.2204460492503131e-016 | |
238 | << std::endl; | |
239 | //] [epsilon_2] | |
240 | } | |
241 | { | |
242 | //[epsilon_3 | |
243 | std::cout.precision(std::numeric_limits<double>::max_digits10); | |
244 | double d = 1.; | |
245 | double eps = std::numeric_limits<double>::epsilon(); | |
246 | double dpeps = d + eps/2; | |
247 | ||
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 | |
252 | << std::endl; | |
253 | //] [epsilon_3] | |
254 | } | |
255 | ||
256 | { | |
257 | typedef double RealType; | |
258 | //[epsilon_4 | |
259 | /*`A tolerance might be defined using this version of epsilon thus: | |
260 | */ | |
261 | RealType tolerance = boost::math::tools::epsilon<RealType>() * 2; | |
262 | //] [epsilon_4] | |
263 | } | |
264 | ||
265 | { | |
266 | //[digits10_5 | |
267 | -(std::numeric_limits<double>::max)() == std::numeric_limits<double>::lowest(); | |
268 | //] [/digits10_5] | |
269 | } | |
270 | ||
271 | { | |
272 | //[denorm_min_1 | |
273 | std::cout.precision(std::numeric_limits<double>::max_digits10); | |
274 | if (std::numeric_limits<double>::has_denorm == std::denorm_present) | |
275 | { | |
276 | double d = std::numeric_limits<double>::denorm_min(); | |
277 | ||
278 | std::cout << d << std::endl; // 4.9406564584124654e-324 | |
279 | ||
280 | int exponent; | |
281 | ||
282 | double significand = frexp(d, &exponent); | |
283 | std::cout << "exponent = " << std::hex << exponent << std::endl; // fffffbcf | |
284 | std::cout << "significand = " << std::hex << significand << std::endl; // 0.50000000000000000 | |
285 | } | |
286 | else | |
287 | { | |
288 | std::cout << "No denormalization. " << std::endl; | |
289 | } | |
290 | //] [denorm_min_1] | |
291 | } | |
292 | ||
293 | { | |
294 | //[round_error_1 | |
295 | double round_err = std::numeric_limits<double>::epsilon() // 2.2204460492503131e-016 | |
296 | * std::numeric_limits<double>::round_error(); // 1/2 | |
297 | std::cout << round_err << std::endl; // 1.1102230246251565e-016 | |
298 | //] [/round_error_1] | |
299 | } | |
300 | ||
301 | { | |
302 | typedef double T; | |
303 | //[tolerance_1 | |
304 | /*`For example, if we want a tolerance that might suit about 9 arithmetical operations, | |
305 | say sqrt(9) = 3, we could define: | |
306 | */ | |
307 | ||
308 | T tolerance = 3 * std::numeric_limits<T>::epsilon(); | |
309 | ||
310 | /*`This is very widely used in Boost.Math testing | |
311 | with Boost.Test's macro `BOOST_CHECK_CLOSE_FRACTION` | |
312 | */ | |
313 | ||
314 | T expected = 1.0; | |
315 | T calculated = 1.0 + std::numeric_limits<T>::epsilon(); | |
316 | ||
317 | BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance); | |
318 | ||
319 | //] [/tolerance_1] | |
320 | } | |
321 | ||
b32b8144 | 322 | #if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32)) |
7c673cae FG |
323 | { |
324 | //[tolerance_2 | |
325 | ||
326 | using boost::multiprecision::number; | |
327 | using boost::multiprecision::cpp_dec_float; | |
328 | using boost::multiprecision::et_off; | |
329 | ||
330 | typedef number<cpp_dec_float<50>, et_off > cpp_dec_float_50; // 50 decimal digits. | |
331 | /*`[note that Boost.Test does not yet allow floating-point comparisons with expression templates on, | |
332 | so the default expression template parameter has been replaced by `et_off`.] | |
333 | */ | |
334 | ||
335 | cpp_dec_float_50 tolerance = 3 * std::numeric_limits<cpp_dec_float_50>::epsilon(); | |
336 | cpp_dec_float_50 expected = boost::math::constants::two_pi<cpp_dec_float_50>(); | |
337 | cpp_dec_float_50 calculated = 2 * boost::math::constants::pi<cpp_dec_float_50>(); | |
338 | ||
339 | BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance); | |
340 | ||
341 | //] [/tolerance_2] | |
342 | } | |
343 | ||
344 | { | |
345 | //[tolerance_3 | |
346 | ||
347 | using boost::multiprecision::cpp_bin_float_quad; | |
348 | ||
349 | cpp_bin_float_quad tolerance = 3 * std::numeric_limits<cpp_bin_float_quad>::epsilon(); | |
350 | cpp_bin_float_quad expected = boost::math::constants::two_pi<cpp_bin_float_quad>(); | |
351 | cpp_bin_float_quad calculated = 2 * boost::math::constants::pi<cpp_bin_float_quad>(); | |
352 | ||
353 | BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance); | |
354 | ||
355 | //] [/tolerance_3] | |
356 | } | |
357 | ||
358 | { | |
359 | //[nan_1] | |
360 | ||
361 | /*`NaN can be used with binary multiprecision types like `cpp_bin_float_quad`: | |
362 | */ | |
363 | using boost::multiprecision::cpp_bin_float_quad; | |
364 | ||
365 | if (std::numeric_limits<cpp_bin_float_quad>::has_quiet_NaN == true) | |
366 | { | |
367 | cpp_bin_float_quad tolerance = 3 * std::numeric_limits<cpp_bin_float_quad>::epsilon(); | |
368 | ||
369 | cpp_bin_float_quad NaN = std::numeric_limits<cpp_bin_float_quad>::quiet_NaN(); | |
370 | std::cout << "cpp_bin_float_quad NaN is " << NaN << std::endl; // cpp_bin_float_quad NaN is nan | |
371 | ||
372 | cpp_bin_float_quad expected = NaN; | |
373 | cpp_bin_float_quad calculated = 2 * NaN; | |
374 | // Comparisons of NaN's always fail: | |
375 | bool b = expected == calculated; | |
376 | std::cout << b << std::endl; | |
377 | BOOST_CHECK_NE(expected, expected); | |
378 | BOOST_CHECK_NE(expected, calculated); | |
379 | } | |
380 | else | |
381 | { | |
382 | std::cout << "Type " << typeid(cpp_bin_float_quad).name() << " does not have NaNs!" << std::endl; | |
383 | } | |
384 | ||
385 | //] [/nan_1] | |
386 | } | |
387 | ||
388 | { | |
389 | //[facet_1] | |
390 | ||
391 | /*` | |
392 | See [@boost:/libs/math/example/nonfinite_facet_sstream.cpp] | |
393 | and we also need | |
394 | ||
395 | #include <boost/math/special_functions/nonfinite_num_facets.hpp> | |
396 | ||
397 | Then we can equally well use a multiprecision type cpp_bin_float_quad: | |
398 | ||
399 | */ | |
400 | using boost::multiprecision::cpp_bin_float_quad; | |
401 | ||
402 | typedef cpp_bin_float_quad T; | |
403 | ||
404 | using boost::math::nonfinite_num_put; | |
405 | using boost::math::nonfinite_num_get; | |
406 | { | |
407 | std::locale old_locale; | |
408 | std::locale tmp_locale(old_locale, new nonfinite_num_put<char>); | |
409 | std::locale new_locale(tmp_locale, new nonfinite_num_get<char>); | |
410 | std::stringstream ss; | |
411 | ss.imbue(new_locale); | |
412 | T inf = std::numeric_limits<T>::infinity(); | |
413 | ss << inf; // Write out. | |
414 | assert(ss.str() == "inf"); | |
415 | T r; | |
416 | ss >> r; // Read back in. | |
417 | assert(inf == r); // Confirms that the floating-point values really are identical. | |
418 | std::cout << "infinity output was " << ss.str() << std::endl; | |
419 | std::cout << "infinity input was " << r << std::endl; | |
420 | } | |
421 | ||
422 | /*` | |
423 | infinity output was inf | |
424 | infinity input was inf | |
425 | ||
426 | Similarly we can do the same with NaN (except that we cannot use `assert`) | |
427 | */ | |
428 | { | |
429 | std::locale old_locale; | |
430 | std::locale tmp_locale(old_locale, new nonfinite_num_put<char>); | |
431 | std::locale new_locale(tmp_locale, new nonfinite_num_get<char>); | |
432 | std::stringstream ss; | |
433 | ss.imbue(new_locale); | |
434 | T n; | |
435 | T NaN = std::numeric_limits<T>::quiet_NaN(); | |
436 | ss << NaN; // Write out. | |
437 | assert(ss.str() == "nan"); | |
438 | std::cout << "NaN output was " << ss.str() << std::endl; | |
439 | ss >> n; // Read back in. | |
440 | std::cout << "NaN input was " << n << std::endl; | |
441 | } | |
442 | /*` | |
443 | NaN output was nan | |
444 | NaN input was nan | |
445 | ||
446 | */ | |
447 | //] [/facet_1] | |
448 | } | |
449 | ||
b32b8144 FG |
450 | #endif |
451 | #endif | |
7c673cae FG |
452 | } // BOOST_AUTO_TEST_CASE(test_numeric_limits_snips) |
453 |