1 // Use, modification and distribution are subject to the
2 // Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt
4 // or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 // Copyright Paul A. Bristow 2019.
7 // Copyright Christopher Kormanyos 2012.
8 // Copyright John Maddock 2012.
9
10 // This file is written to be included from a Quickbook .qbk document.
11 // It can be compiled by the C++ compiler, and run. Any output can
12 // also be added here as comment or included or pasted in elsewhere.
13 // Caution: this file contains Quickbook markup as well as code
14 // and comments: don't change any of the special comment markups!
15
16 #ifdef _MSC_VER
17 #pragma warning(disable : 4512) // assignment operator could not be generated.
18 #pragma warning(disable : 4996)
19 #endif
20
21 //[big_seventh_example_1
22
23 /*`[h5 Using Boost.Multiprecision `cpp_float` types for numerical calculations with higher precision than built-in `long double`.]
24
25 The Boost.Multiprecision library can be used for computations requiring precision
26 exceeding that of standard built-in types such as `float`, `double`
27 and `long double`. For extended-precision calculations, Boost.Multiprecision
28 supplies several template data types called `cpp_bin_float_`.
29
30 The number of decimal digits of precision is fixed at compile-time via template parameter.
31
32 To use these floating-point types and
33 [@https://www.boost.org/doc/libs/release/libs/math/doc/html/constants.html Boost.Math collection of high-precision constants],
34 we need some includes:
35 */
36
37 #include <boost/math/constants/constants.hpp>
38
39 #include <boost/multiprecision/cpp_bin_float.hpp>
40 // that includes some predefined typedefs that can be used thus:
41 // using boost::multiprecision::cpp_bin_float_quad;
42 // using boost::multiprecision::cpp_bin_float_50;
43 // using boost::multiprecision::cpp_bin_float_100;
44
45 #include <iostream>
46 #include <limits>
47 #include <type_traits>
48
49 /*` So now we can demonstrate with some trivial calculations:
50 */
51
52 //] //[big_seventh_example_1]
53
no_et()54 void no_et()
55 {
56 using namespace boost::multiprecision;
57
58 std::cout.setf(std::ios_base::boolalpha);
59
60 typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_on> cpp_bin_float_quad_et_on;
61 typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_quad_et_off;
62
63 typedef number<backends::cpp_bin_float<113, backends::digit_base_2, void, boost::int16_t, -16382, 16383>, et_off> cpp_bin_float_oct;
64
65
66 cpp_bin_float_quad x("42.");
67 std::cout << "cpp_bin_float_quad x = " << x << std::endl;
68
69 cpp_bin_float_quad_et_on q("42.");
70
71 std::cout << "std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_off>::value is " << std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_off>::value << std::endl;
72 std::cout << "std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_on>::value is " << std::is_same<cpp_bin_float_quad, cpp_bin_float_quad_et_on>::value << std::endl;
73
74 std::cout << "cpp_bin_float_quad_et_on q = " << q << std::endl;
75 cpp_bin_float_50 y("42."); // typedef number<backends::cpp_bin_float<50> > cpp_bin_float_50;
76
77 std::cout << "cpp_bin_float_50 y = " << y << std::endl;
78
79 typedef number<backends::cpp_bin_float<50>, et_off > cpp_bin_float_50_no_et;
80 typedef number<backends::cpp_bin_float<50>, et_on > cpp_bin_float_50_et;
81
82 cpp_bin_float_50_no_et z("42."); // typedef number<backends::cpp_bin_float<50> > cpp_bin_float_50;
83
84 std::cout << "cpp_bin_float_50_no_et z = " << z << std::endl;
85
86 std::cout << " std::is_same<cpp_bin_float_50, cpp_bin_float_50_no_et>::value is " << std::is_same<cpp_bin_float_50, cpp_bin_float_50_no_et>::value << std::endl;
87 std::cout << " std::is_same<cpp_bin_float_50_et, cpp_bin_float_50_no_et>::value is " << std::is_same<cpp_bin_float_50_et, cpp_bin_float_50_no_et>::value << std::endl;
88
89 } // void no_et()
90
main()91 int main()
92 {
93
94 no_et();
95
96 return 0;
97
98
99 //[big_seventh_example_2
100 /*`Using `typedef cpp_bin_float_50` hides the complexity of multiprecision,
101 allows us to define variables with 50 decimal digit precision just like built-in `double`.
102 */
103 using boost::multiprecision::cpp_bin_float_50;
104
105 cpp_bin_float_50 seventh = cpp_bin_float_50(1) / 7; // 1 / 7
106
107 /*`By default, output would only show the standard 6 decimal digits,
108 so set precision to show all 50 significant digits, including any trailing zeros.
109 */
110 std::cout.precision(std::numeric_limits<cpp_bin_float_50>::digits10);
111 std::cout << std::showpoint << std::endl; // Append any trailing zeros.
112 std::cout << seventh << std::endl;
113 /*`which outputs:
114
115 0.14285714285714285714285714285714285714285714285714
116
117 We can also use __math_constants like [pi],
118 guaranteed to be initialized with the very last bit of precision (__ULP) for the floating-point type.
119 */
120 std::cout << "pi = " << boost::math::constants::pi<cpp_bin_float_50>() << std::endl;
121 cpp_bin_float_50 circumference = boost::math::constants::pi<cpp_bin_float_50>() * 2 * seventh;
122 std::cout << "c = " << circumference << std::endl;
123
124 /*`which outputs
125
126 pi = 3.1415926535897932384626433832795028841971693993751
127
128 c = 0.89759790102565521098932668093700082405633411410717
129 */
130 //] [/big_seventh_example_2]
131
132 //[big_seventh_example_3
133 /*`So using `cpp_bin_float_50` looks like a simple 'drop-in' for the __fundamental_type like 'double',
134 but beware of loss of precision from construction or conversion from `double` or other lower precision types.
135 This is a mistake that is very easy to make,
136 and very difficult to detect because the loss of precision is only visible after the 17th decimal digit.
137
138 We can show this by constructing from `double`, (avoiding the schoolboy-error `double d7 = 1 / 7;` giving zero!)
139 */
140
141 double d7 = 1. / 7; //
142 std::cout << "d7 = " << d7 << std::endl;
143
144 cpp_bin_float_50 seventh_0 = cpp_bin_float_50(1 / 7); // Avoid the schoolboy-error 1 / 7 == 0!)
145 std::cout << "seventh_0 = " << seventh_0 << std::endl;
146 // seventh_double0 = 0.0000000000000000000000000000000000000000000000000
147
148 cpp_bin_float_50 seventh_double = cpp_bin_float_50(1. / 7); // Construct from double!
149 std::cout << "seventh_double = " << seventh_double << std::endl; // Boost.Multiprecision post-school error!
150 // seventh_double = 0.14285714285714284921269268124888185411691665649414
151
152 /*`Did you spot the mistake? After the 17th decimal digit, result is random!
153
154 14285714285714 should be recurring.
155 */
156
157 cpp_bin_float_50 seventh_big(1); // 1
158 seventh_big /= 7;
159 std::cout << "seventh_big = " << seventh_big << std::endl; //
160 // seventh_big = 0.14285714285714285714285714285714285714285714285714
161 /*`Note the recurring 14285714285714 pattern as expected.
162
163 As one would expect, the variable can be `const` (but sadly [*not yet `constexpr`]).
164 */
165
166 const cpp_bin_float_50 seventh_const(cpp_bin_float_50(1) / 7);
167 std::cout << "seventh_const = " << seventh_const << std::endl;
168 // seventh_const = 0.14285714285714285714285714285714285714285714285714
169
170 /*`The full output is:
171 */
172
173 //] [/big_seventh_example_3
174
175 //[big_seventh_example_constexpr
176
177 // Sadly we cannot (yet) write:
178 // constexpr cpp_bin_float_50 any_constexpr(0);
179
180 // constexpr cpp_bin_float_50 seventh_constexpr (cpp_bin_float_50(1) / 7);
181 // std::cout << "seventh_constexpr = " << seventh_constexpr << std::endl; //
182 // nor use the macro BOOST_CONSTEXPR_OR_CONST unless it returns `const`
183 // BOOST_CONSTEXPR_OR_CONST cpp_bin_float_50 seventh_constexpr(seventh_const);
184
185 //] [/big_seventh_example_constexpr
186
187 return 0;
188 } // int main()
189
190 /*
191 //[big_seventh_example_output
192
193 0.14285714285714285714285714285714285714285714285714
194 pi = 3.1415926535897932384626433832795028841971693993751
195 c = 0.89759790102565521098932668093700082405633411410717
196 d7 = 0.14285714285714284921269268124888185411691665649414
197 seventh_0 = 0.0000000000000000000000000000000000000000000000000
198 seventh_double = 0.14285714285714284921269268124888185411691665649414
199 seventh_big = 0.14285714285714285714285714285714285714285714285714
200 seventh_const = 0.14285714285714285714285714285714285714285714285714
201
202 //] //[big_seventh_example_output]
203
204 */
205