]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/multiprecision/test/test_cpp_bin_float_io.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / multiprecision / test / test_cpp_bin_float_io.cpp
1 // Copyright John Maddock 2013.
2
3 // Use, modification and distribution are subject to the
4 // Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8 #ifdef _MSC_VER
9 #define _SCL_SECURE_NO_WARNINGS
10 #endif
11
12 #include <boost/multiprecision/cpp_bin_float.hpp>
13
14 #include <boost/random/mersenne_twister.hpp>
15 #include <boost/random/uniform_int.hpp>
16 #include <boost/chrono.hpp>
17 #include "test.hpp"
18 #include <boost/array.hpp>
19 #include <iostream>
20 #include <iomanip>
21
22 #ifdef BOOST_MSVC
23 #pragma warning(disable : 4127)
24 #endif
25
26 template <class Clock>
27 struct stopwatch
28 {
29 typedef typename Clock::duration duration;
30 stopwatch()
31 {
32 m_start = Clock::now();
33 }
34 duration elapsed()
35 {
36 return Clock::now() - m_start;
37 }
38 void reset()
39 {
40 m_start = Clock::now();
41 }
42
43 private:
44 typename Clock::time_point m_start;
45 };
46
47 void print_flags(std::ios_base::fmtflags f)
48 {
49 std::cout << "Formatting flags were: ";
50 if (f & std::ios_base::scientific)
51 std::cout << "scientific ";
52 if (f & std::ios_base::fixed)
53 std::cout << "fixed ";
54 if (f & std::ios_base::showpoint)
55 std::cout << "showpoint ";
56 if (f & std::ios_base::showpos)
57 std::cout << "showpos ";
58 std::cout << std::endl;
59 }
60
61 template <class T>
62 void test()
63 {
64 typedef T mp_t;
65 boost::array<std::ios_base::fmtflags, 9> f =
66 {{std::ios_base::fmtflags(0), std::ios_base::showpoint, std::ios_base::showpos, std::ios_base::scientific, std::ios_base::scientific | std::ios_base::showpos,
67 std::ios_base::scientific | std::ios_base::showpoint, std::ios_base::fixed, std::ios_base::fixed | std::ios_base::showpoint,
68 std::ios_base::fixed | std::ios_base::showpos}};
69
70 boost::array<boost::array<const char*, 13 * 9>, 40> string_data = {{
71 #include "libs/multiprecision/test/string_data.ipp"
72 }};
73
74 double num = 123456789.0;
75 double denom = 1;
76 double val = num;
77 for (unsigned j = 0; j < 40; ++j)
78 {
79 unsigned col = 0;
80 for (unsigned prec = 1; prec < 14; ++prec)
81 {
82 for (unsigned i = 0; i < f.size(); ++i, ++col)
83 {
84 std::stringstream ss;
85 ss.precision(prec);
86 ss.flags(f[i]);
87 ss << mp_t(val);
88 const char* expect = string_data[j][col];
89 if (ss.str() != expect)
90 {
91 std::cout << std::setprecision(20) << "Testing value " << val << std::endl;
92 print_flags(f[i]);
93 std::cout << "Precision is: " << prec << std::endl;
94 std::cout << "Got: " << ss.str() << std::endl;
95 std::cout << "Expected: " << expect << std::endl;
96 ++boost::detail::test_errors();
97 mp_t(val).str(prec, f[i]); // for debugging
98 }
99 }
100 }
101 num = -num;
102 if (j & 1)
103 denom *= 8;
104 val = num / denom;
105 }
106
107 boost::array<const char*, 13 * 9> zeros =
108 {{"0", "0.", "+0", "0.0e+00", "+0.0e+00", "0.0e+00", "0.0", "0.0", "+0.0", "0", "0.0", "+0", "0.00e+00", "+0.00e+00", "0.00e+00", "0.00", "0.00", "+0.00", "0", "0.00", "+0", "0.000e+00", "+0.000e+00", "0.000e+00", "0.000", "0.000", "+0.000", "0", "0.000", "+0", "0.0000e+00", "+0.0000e+00", "0.0000e+00", "0.0000", "0.0000", "+0.0000", "0", "0.0000", "+0", "0.00000e+00", "+0.00000e+00", "0.00000e+00", "0.00000", "0.00000", "+0.00000", "0", "0.00000", "+0", "0.000000e+00", "+0.000000e+00", "0.000000e+00", "0.000000", "0.000000", "+0.000000", "0", "0.000000", "+0", "0.0000000e+00", "+0.0000000e+00", "0.0000000e+00", "0.0000000", "0.0000000", "+0.0000000", "0", "0.0000000", "+0", "0.00000000e+00", "+0.00000000e+00", "0.00000000e+00", "0.00000000", "0.00000000", "+0.00000000", "0", "0.00000000", "+0", "0.000000000e+00", "+0.000000000e+00", "0.000000000e+00", "0.000000000", "0.000000000", "+0.000000000", "0", "0.000000000", "+0", "0.0000000000e+00", "+0.0000000000e+00", "0.0000000000e+00", "0.0000000000", "0.0000000000", "+0.0000000000", "0", "0.0000000000", "+0", "0.00000000000e+00", "+0.00000000000e+00", "0.00000000000e+00", "0.00000000000", "0.00000000000", "+0.00000000000", "0", "0.00000000000", "+0", "0.000000000000e+00", "+0.000000000000e+00", "0.000000000000e+00", "0.000000000000", "0.000000000000", "+0.000000000000", "0", "0.000000000000", "+0", "0.0000000000000e+00", "+0.0000000000000e+00", "0.0000000000000e+00", "0.0000000000000", "0.0000000000000", "+0.0000000000000"}};
109
110 unsigned col = 0;
111 val = 0;
112 for (unsigned prec = 1; prec < 14; ++prec)
113 {
114 for (unsigned i = 0; i < f.size(); ++i, ++col)
115 {
116 std::stringstream ss;
117 ss.precision(prec);
118 ss.flags(f[i]);
119 ss << mp_t(val);
120 const char* expect = zeros[col];
121 if (ss.str() != expect)
122 {
123 std::cout << std::setprecision(20) << "Testing value " << val << std::endl;
124 print_flags(f[i]);
125 std::cout << "Precision is: " << prec << std::endl;
126 std::cout << "Got: " << ss.str() << std::endl;
127 std::cout << "Expected: " << expect << std::endl;
128 ++boost::detail::test_errors();
129 mp_t(val).str(prec, f[i]); // for debugging
130 }
131 }
132 }
133
134 if (std::numeric_limits<mp_t>::has_infinity)
135 {
136 T val = std::numeric_limits<T>::infinity();
137 BOOST_CHECK_EQUAL(val.str(), "inf");
138 BOOST_CHECK_EQUAL(val.str(0, std::ios_base::showpos), "+inf");
139 val = -val;
140 BOOST_CHECK_EQUAL(val.str(), "-inf");
141 BOOST_CHECK_EQUAL(val.str(0, std::ios_base::showpos), "-inf");
142
143 val = static_cast<T>("inf");
144 BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
145 val = static_cast<T>("+inf");
146 BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
147 val = static_cast<T>("-inf");
148 BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
149 }
150 if (std::numeric_limits<mp_t>::has_quiet_NaN)
151 {
152 T val = std::numeric_limits<T>::quiet_NaN();
153 BOOST_CHECK_EQUAL(val.str(), "nan");
154 val = static_cast<T>("nan");
155 BOOST_CHECK((boost::math::isnan)(val));
156 }
157 //
158 // Min and max values:
159 //
160 T t((std::numeric_limits<T>::max)().str(std::numeric_limits<T>::max_digits10, std::ios_base::scientific));
161 BOOST_CHECK_EQUAL(t, (std::numeric_limits<T>::max)());
162 t = T((std::numeric_limits<T>::min)().str(std::numeric_limits<T>::max_digits10, std::ios_base::scientific));
163 BOOST_CHECK_EQUAL(t, (std::numeric_limits<T>::min)());
164 t = T((std::numeric_limits<T>::lowest)().str(std::numeric_limits<T>::max_digits10, std::ios_base::scientific));
165 BOOST_CHECK_EQUAL(t, (std::numeric_limits<T>::lowest)());
166 }
167
168 template <class T>
169 T generate_random()
170 {
171 typedef typename T::backend_type::exponent_type e_type;
172 static boost::random::mt19937 gen;
173 T val = gen();
174 T prev_val = -1;
175 while (val != prev_val)
176 {
177 val *= (gen.max)();
178 prev_val = val;
179 val += gen();
180 }
181 e_type e;
182 val = frexp(val, &e);
183
184 static boost::random::uniform_int_distribution<e_type> ui(0, std::numeric_limits<T>::max_exponent);
185 return ldexp(val, ui(gen));
186 }
187
188 template <class T>
189 void do_round_trip(const T& val, std::ios_base::fmtflags f)
190 {
191 std::stringstream ss;
192 #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
193 ss << std::setprecision(std::numeric_limits<T>::max_digits10);
194 #else
195 ss << std::setprecision(std::numeric_limits<T>::digits10 + 3);
196 #endif
197 ss.flags(f);
198 ss << val;
199 T new_val = static_cast<T>(ss.str());
200 BOOST_CHECK_EQUAL(new_val, val);
201 new_val = static_cast<T>(val.str(0, f));
202 BOOST_CHECK_EQUAL(new_val, val);
203 }
204
205 template <class T>
206 void do_round_trip(const T& val)
207 {
208 do_round_trip(val, std::ios_base::fmtflags(0));
209 do_round_trip(val, std::ios_base::fmtflags(std::ios_base::scientific));
210 if ((fabs(val) > 1) && (fabs(val) < 1e100))
211 do_round_trip(val, std::ios_base::fmtflags(std::ios_base::fixed));
212
213 static int error_count = 0;
214
215 if (error_count != boost::detail::test_errors())
216 {
217 error_count = boost::detail::test_errors();
218 std::cout << "Errors occured while testing value....";
219 if (val.backend().sign())
220 std::cout << "-";
221 std::cout << boost::multiprecision::cpp_int(val.backend().bits()) << "e" << val.backend().exponent() << std::endl;
222 }
223 }
224
225 template <class T>
226 void test_round_trip()
227 {
228 std::cout << "Testing type " << typeid(T).name() << std::endl;
229 std::cout << "digits = " << std::numeric_limits<T>::digits << std::endl;
230 std::cout << "digits10 = " << std::numeric_limits<T>::digits10 << std::endl;
231 std::cout << "max_digits10 = " << std::numeric_limits<T>::max_digits10 << std::endl;
232
233 stopwatch<boost::chrono::high_resolution_clock> w;
234
235 #ifndef CI_SUPPRESS_KNOWN_ISSUES
236 while (boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count() < 200)
237 #else
238 while (boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count() < 50)
239 #endif
240 {
241 T val = generate_random<T>();
242 do_round_trip(val);
243 do_round_trip(T(-val));
244 do_round_trip(T(1 / val));
245 do_round_trip(T(-1 / val));
246
247 if (boost::detail::test_errors() > 200)
248 break; // escape if there are too many errors.
249 }
250
251 std::cout << "Execution time = " << boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count() << "s" << std::endl;
252 }
253
254 #if !defined(TEST1) && !defined(TEST2)
255 #define TEST1
256 #define TEST2
257 #endif
258
259 int main()
260 {
261 using namespace boost::multiprecision;
262 #ifdef TEST1
263 test<number<cpp_bin_float<113, digit_base_2> > >();
264 test_round_trip<number<cpp_bin_float<113, digit_base_2> > >();
265 #endif
266 #ifdef TEST2
267 test<number<cpp_bin_float<53, digit_base_2> > >();
268 test_round_trip<number<cpp_bin_float<53, digit_base_2> > >();
269 #endif
270 return boost::report_errors();
271 }