numeric_limits_snips.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. // Copyright Paul A. Bristow 2013
  2. // Copyright John Maddock 2013
  3. // Copyright Christopher Kormanyos
  4. // Use, modification and distribution are subject to the
  5. // Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt
  7. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. // Examples of numeric_limits usage as snippets for multiprecision documentation.
  9. // Includes text as Quickbook comments.
  10. #include <iostream>
  11. #include <iomanip>
  12. #include <string>
  13. #include <sstream>
  14. #include <limits> // numeric_limits
  15. #include <iomanip>
  16. #include <locale>
  17. #include <boost/assert.hpp>
  18. #include <boost/math/constants/constants.hpp>
  19. #include <boost/math/special_functions/nonfinite_num_facets.hpp>
  20. #include <boost/math/special_functions/factorials.hpp>
  21. #include <boost/math/special_functions/next.hpp>
  22. #include <boost/math/tools/precision.hpp>
  23. #include <boost/multiprecision/cpp_dec_float.hpp> // is decimal.
  24. #include <boost/multiprecision/cpp_bin_float.hpp> // is binary.
  25. #define BOOST_TEST_MAIN
  26. #include <boost/test/unit_test.hpp> // Boost.Test
  27. #include <boost/test/floating_point_comparison.hpp>
  28. static long double const log10Two = 0.30102999566398119521373889472449L; // log10(2.)
  29. template <typename T>
  30. int max_digits10()
  31. {
  32. int significand_digits = std::numeric_limits<T>::digits;
  33. // BOOST_CONSTEXPR_OR_CONST int significand_digits = std::numeric_limits<T>::digits;
  34. return static_cast<int>(ceil(1 + significand_digits * log10Two));
  35. } // template <typename T> int max_digits10()
  36. // Used to test max_digits10<>() function below.
  37. //#define BOOST_NO_CXX11_NUMERIC_LIMITS
  38. BOOST_AUTO_TEST_CASE(test_numeric_limits_snips)
  39. {
  40. #if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(BOOST_MSVC) && (BOOST_MSVC == 1600))
  41. try
  42. {
  43. // Example of portable way to get `std::numeric_limits<T>::max_digits10`.
  44. //[max_digits10_1
  45. /*`For example, to be portable (including obselete platforms) for type `T` where `T` may be:
  46. `float`, `double`, `long double`, `128-bit quad type`, `cpp_bin_float_50` ...
  47. */
  48. typedef float T;
  49. #if defined BOOST_NO_CXX11_NUMERIC_LIMITS
  50. // No max_digits10 implemented.
  51. std::cout.precision(max_digits10<T>());
  52. #else
  53. #if(_MSC_VER <= 1600)
  54. // Wrong value for std::numeric_limits<float>::max_digits10.
  55. std::cout.precision(max_digits10<T>());
  56. #else // Use the C++11 max_digits10.
  57. std::cout.precision(std::numeric_limits<T>::max_digits10);
  58. #endif
  59. #endif
  60. std::cout << "std::cout.precision(max_digits10) = " << std::cout.precision() << std::endl; // 9
  61. double x = 1.2345678901234567889;
  62. std::cout << "x = " << x << std::endl; //
  63. /*`which should output:
  64. std::cout.precision(max_digits10) = 9
  65. x = 1.23456789
  66. */
  67. //] [/max_digits10_1]
  68. {
  69. //[max_digits10_2
  70. double write = 2./3; // Any arbitrary value that cannot be represented exactly.
  71. double read = 0;
  72. std::stringstream s;
  73. s.precision(std::numeric_limits<double>::digits10); // or `float64_t` for 64-bit IEE754 double.
  74. s << write;
  75. s >> read;
  76. if(read != write)
  77. {
  78. std::cout << std::setprecision(std::numeric_limits<double>::digits10)
  79. << read << " != " << write << std::endl;
  80. }
  81. //] [/max_digits10_2]
  82. // 0.666666666666667 != 0.666666666666667
  83. }
  84. {
  85. //[max_digits10_3
  86. double pi = boost::math::double_constants::pi;
  87. std::cout.precision(std::numeric_limits<double>::max_digits10);
  88. std::cout << pi << std::endl; // 3.1415926535897931
  89. //] [/max_digits10_3]
  90. }
  91. {
  92. //[max_digits10_4
  93. /*`and similarly for a much higher precision type:
  94. */
  95. using namespace boost::multiprecision;
  96. typedef number<cpp_dec_float<50> > cpp_dec_float_50; // 50 decimal digits.
  97. using boost::multiprecision::cpp_dec_float_50;
  98. cpp_dec_float_50 pi = boost::math::constants::pi<cpp_dec_float_50>();
  99. std::cout.precision(std::numeric_limits<cpp_dec_float_50>::max_digits10);
  100. std::cout << pi << std::endl;
  101. // 3.141592653589793238462643383279502884197169399375105820974944592307816406
  102. //] [/max_digits10_4]
  103. }
  104. {
  105. //[max_digits10_5
  106. for (int i = 2; i < 15; i++)
  107. {
  108. std::cout << std::setw(std::numeric_limits<int>::max_digits10)
  109. << boost::math::factorial<double>(i) << std::endl;
  110. }
  111. //] [/max_digits10_5]
  112. }
  113. }
  114. catch(std::exception ex)
  115. {
  116. std::cout << "Caught Exception " << ex.what() << std::endl;
  117. }
  118. {
  119. //[max_digits10_6
  120. typedef double T;
  121. bool denorm = std::numeric_limits<T>::denorm_min() < (std::numeric_limits<T>::min)();
  122. BOOST_ASSERT(denorm);
  123. //] [/max_digits10_6]
  124. }
  125. {
  126. unsigned char c = 255;
  127. std::cout << "char c = " << (int)c << std::endl;
  128. }
  129. {
  130. //[digits10_1
  131. std::cout
  132. << std::setw(std::numeric_limits<short>::digits10 +1 +1) // digits10+1, and +1 for sign.
  133. << std::showpos << (std::numeric_limits<short>::max)() // +32767
  134. << std::endl
  135. << std::setw(std::numeric_limits<short>::digits10 +1 +1)
  136. << (std::numeric_limits<short>::min)() << std::endl; // -32767
  137. //] [/digits10_1]
  138. }
  139. {
  140. //[digits10_2
  141. std::cout
  142. << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
  143. << std::showpos << (std::numeric_limits<unsigned short>::max)() // 65535
  144. << std::endl
  145. << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
  146. << (std::numeric_limits<unsigned short>::min)() << std::endl; // 0
  147. //] [/digits10_2]
  148. }
  149. std::cout <<std::noshowpos << std::endl;
  150. {
  151. //[digits10_3
  152. std::cout.precision(std::numeric_limits<double>::max_digits10);
  153. double d = 1e15;
  154. double dp1 = d+1;
  155. std::cout << d << "\n" << dp1 << std::endl;
  156. // 1000000000000000
  157. // 1000000000000001
  158. std::cout << dp1 - d << std::endl; // 1
  159. //] [/digits10_3]
  160. }
  161. {
  162. //[digits10_4
  163. std::cout.precision(std::numeric_limits<double>::max_digits10);
  164. double d = 1e16;
  165. double dp1 = d+1;
  166. std::cout << d << "\n" << dp1 << std::endl;
  167. // 10000000000000000
  168. // 10000000000000000
  169. std::cout << dp1 - d << std::endl; // 0 !!!
  170. //] [/digits10_4]
  171. }
  172. {
  173. //[epsilon_1
  174. std::cout.precision(std::numeric_limits<double>::max_digits10);
  175. double d = 1.;
  176. double eps = std::numeric_limits<double>::epsilon();
  177. double dpeps = d+eps;
  178. std::cout << std::showpoint // Ensure all trailing zeros are shown.
  179. << d << "\n" // 1.0000000000000000
  180. << dpeps << std::endl; // 2.2204460492503131e-016
  181. std::cout << dpeps - d // 1.0000000000000002
  182. << std::endl;
  183. //] [epsilon_1]
  184. }
  185. {
  186. //[epsilon_2
  187. double one = 1.;
  188. double nad = boost::math::float_next(one);
  189. std::cout << nad << "\n" // 1.0000000000000002
  190. << nad - one // 2.2204460492503131e-016
  191. << std::endl;
  192. //] [epsilon_2]
  193. }
  194. {
  195. //[epsilon_3
  196. std::cout.precision(std::numeric_limits<double>::max_digits10);
  197. double d = 1.;
  198. double eps = std::numeric_limits<double>::epsilon();
  199. double dpeps = d + eps/2;
  200. std::cout << std::showpoint // Ensure all trailing zeros are shown.
  201. << dpeps << "\n" // 1.0000000000000000
  202. << eps/2 << std::endl; // 1.1102230246251565e-016
  203. std::cout << dpeps - d // 0.00000000000000000
  204. << std::endl;
  205. //] [epsilon_3]
  206. }
  207. {
  208. typedef double RealType;
  209. //[epsilon_4
  210. /*`A tolerance might be defined using this version of epsilon thus:
  211. */
  212. RealType tolerance = boost::math::tools::epsilon<RealType>() * 2;
  213. //] [epsilon_4]
  214. }
  215. {
  216. //[digits10_5
  217. -(std::numeric_limits<double>::max)() == std::numeric_limits<double>::lowest();
  218. //] [/digits10_5]
  219. // warning C4553: '==': result of expression not used; did you intend '='? is spurious.
  220. }
  221. {
  222. //[denorm_min_1
  223. std::cout.precision(std::numeric_limits<double>::max_digits10);
  224. if (std::numeric_limits<double>::has_denorm == std::denorm_present)
  225. {
  226. double d = std::numeric_limits<double>::denorm_min();
  227. std::cout << d << std::endl; // 4.9406564584124654e-324
  228. int exponent;
  229. double significand = frexp(d, &exponent);
  230. std::cout << "exponent = " << std::hex << exponent << std::endl; // fffffbcf
  231. std::cout << "significand = " << std::hex << significand << std::endl; // 0.50000000000000000
  232. }
  233. else
  234. {
  235. std::cout << "No denormalization. " << std::endl;
  236. }
  237. //] [denorm_min_1]
  238. }
  239. {
  240. //[round_error_1
  241. double round_err = std::numeric_limits<double>::epsilon() // 2.2204460492503131e-016
  242. * std::numeric_limits<double>::round_error(); // 1/2
  243. std::cout << round_err << std::endl; // 1.1102230246251565e-016
  244. //] [/round_error_1]
  245. }
  246. {
  247. typedef double T;
  248. //[tolerance_1
  249. /*`For example, if we want a tolerance that might suit about 9 arithmetical operations,
  250. say sqrt(9) = 3, we could define:
  251. */
  252. T tolerance = 3 * std::numeric_limits<T>::epsilon();
  253. /*`This is very widely used in Boost.Math testing
  254. with Boost.Test's macro `BOOST_CHECK_CLOSE_FRACTION`
  255. */
  256. T expected = 1.0;
  257. T calculated = 1.0 + std::numeric_limits<T>::epsilon();
  258. BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
  259. //] [/tolerance_1]
  260. }
  261. #if !(defined(CI_SUPPRESS_KNOWN_ISSUES) && defined(__GNUC__) && defined(_WIN32))
  262. {
  263. //[tolerance_2
  264. using boost::multiprecision::number;
  265. using boost::multiprecision::cpp_dec_float;
  266. using boost::multiprecision::et_off;
  267. typedef number<cpp_dec_float<50>, et_off > cpp_dec_float_50; // 50 decimal digits.
  268. /*`[note that Boost.Test does not yet allow floating-point comparisons with expression templates on,
  269. so the default expression template parameter has been replaced by `et_off`.]
  270. */
  271. cpp_dec_float_50 tolerance = 3 * std::numeric_limits<cpp_dec_float_50>::epsilon();
  272. cpp_dec_float_50 expected = boost::math::constants::two_pi<cpp_dec_float_50>();
  273. cpp_dec_float_50 calculated = 2 * boost::math::constants::pi<cpp_dec_float_50>();
  274. BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
  275. //] [/tolerance_2]
  276. }
  277. {
  278. //[tolerance_3
  279. using boost::multiprecision::cpp_bin_float_quad;
  280. cpp_bin_float_quad tolerance = 3 * std::numeric_limits<cpp_bin_float_quad>::epsilon();
  281. cpp_bin_float_quad expected = boost::math::constants::two_pi<cpp_bin_float_quad>();
  282. cpp_bin_float_quad calculated = 2 * boost::math::constants::pi<cpp_bin_float_quad>();
  283. BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
  284. //] [/tolerance_3]
  285. }
  286. {
  287. //[tolerance_4
  288. using boost::multiprecision::cpp_bin_float_oct;
  289. cpp_bin_float_oct tolerance = 3 * std::numeric_limits<cpp_bin_float_oct>::epsilon();
  290. cpp_bin_float_oct expected = boost::math::constants::two_pi<cpp_bin_float_oct>();
  291. cpp_bin_float_oct calculated = 2 * boost::math::constants::pi<cpp_bin_float_oct>();
  292. BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
  293. //] [/tolerance_4]
  294. }
  295. {
  296. //[nan_1]
  297. /*`NaN can be used with binary multiprecision types like `cpp_bin_float_quad`:
  298. */
  299. using boost::multiprecision::cpp_bin_float_quad;
  300. if (std::numeric_limits<cpp_bin_float_quad>::has_quiet_NaN == true)
  301. {
  302. cpp_bin_float_quad tolerance = 3 * std::numeric_limits<cpp_bin_float_quad>::epsilon();
  303. cpp_bin_float_quad NaN = std::numeric_limits<cpp_bin_float_quad>::quiet_NaN();
  304. std::cout << "cpp_bin_float_quad NaN is " << NaN << std::endl; // cpp_bin_float_quad NaN is nan
  305. cpp_bin_float_quad expected = NaN;
  306. cpp_bin_float_quad calculated = 2 * NaN;
  307. // Comparisons of NaN's always fail:
  308. bool b = expected == calculated;
  309. std::cout << b << std::endl;
  310. BOOST_CHECK_NE(expected, expected);
  311. BOOST_CHECK_NE(expected, calculated);
  312. }
  313. else
  314. {
  315. std::cout << "Type " << typeid(cpp_bin_float_quad).name() << " does not have NaNs!" << std::endl;
  316. }
  317. //] [/nan_1]
  318. }
  319. {
  320. //[facet_1]
  321. /*`
  322. See [@boost:/libs/math/example/nonfinite_facet_sstream.cpp]
  323. and we also need
  324. #include <boost/math/special_functions/nonfinite_num_facets.hpp>
  325. Then we can equally well use a multiprecision type cpp_bin_float_quad:
  326. */
  327. using boost::multiprecision::cpp_bin_float_quad;
  328. typedef cpp_bin_float_quad T;
  329. using boost::math::nonfinite_num_put;
  330. using boost::math::nonfinite_num_get;
  331. {
  332. std::locale old_locale;
  333. std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
  334. std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
  335. std::stringstream ss;
  336. ss.imbue(new_locale);
  337. T inf = std::numeric_limits<T>::infinity();
  338. ss << inf; // Write out.
  339. BOOST_ASSERT(ss.str() == "inf");
  340. T r;
  341. ss >> r; // Read back in.
  342. BOOST_ASSERT(inf == r); // Confirms that the floating-point values really are identical.
  343. std::cout << "infinity output was " << ss.str() << std::endl;
  344. std::cout << "infinity input was " << r << std::endl;
  345. }
  346. /*`
  347. ``
  348. infinity output was inf
  349. infinity input was inf
  350. ``
  351. Similarly we can do the same with NaN (except that we cannot use `assert` (because any comparisons with NaN always return false).
  352. */
  353. {
  354. std::locale old_locale;
  355. std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
  356. std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
  357. std::stringstream ss;
  358. ss.imbue(new_locale);
  359. T n;
  360. T NaN = std::numeric_limits<T>::quiet_NaN();
  361. ss << NaN; // Write out.
  362. BOOST_ASSERT(ss.str() == "nan");
  363. std::cout << "NaN output was " << ss.str() << std::endl;
  364. ss >> n; // Read back in.
  365. std::cout << "NaN input was " << n << std::endl;
  366. }
  367. /*`
  368. ``
  369. NaN output was nan
  370. NaN input was nan
  371. ``
  372. */
  373. //] [/facet_1]
  374. }
  375. #endif
  376. #endif
  377. } // BOOST_AUTO_TEST_CASE(test_numeric_limits_snips)