]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/multiprecision/test/test_cpp_bin_float_io.cpp
add subtree-ish sources for 12.0.3
[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
48 void print_flags(std::ios_base::fmtflags f)
49 {
50 std::cout << "Formatting flags were: ";
51 if(f & std::ios_base::scientific)
52 std::cout << "scientific ";
53 if(f & std::ios_base::fixed)
54 std::cout << "fixed ";
55 if(f & std::ios_base::showpoint)
56 std::cout << "showpoint ";
57 if(f & std::ios_base::showpos)
58 std::cout << "showpos ";
59 std::cout << std::endl;
60 }
61
62
63 template <class T>
64 void test()
65 {
66 typedef T mp_t;
67 boost::array<std::ios_base::fmtflags, 9> f =
68 {{
69 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,
70 std::ios_base::scientific|std::ios_base::showpoint, std::ios_base::fixed, std::ios_base::fixed|std::ios_base::showpoint,
71 std::ios_base::fixed|std::ios_base::showpos
72 }};
73
74 boost::array<boost::array<const char*, 13 * 9>, 40> string_data = {{
75 #include "libs/multiprecision/test/string_data.ipp"
76 }};
77
78 double num = 123456789.0;
79 double denom = 1;
80 double val = num;
81 for(unsigned j = 0; j < 40; ++j)
82 {
83 unsigned col = 0;
84 for(unsigned prec = 1; prec < 14; ++prec)
85 {
86 for(unsigned i = 0; i < f.size(); ++i, ++col)
87 {
88 std::stringstream ss;
89 ss.precision(prec);
90 ss.flags(f[i]);
91 ss << mp_t(val);
92 const char* expect = string_data[j][col];
93 if(ss.str() != expect)
94 {
95 std::cout << std::setprecision(20) << "Testing value " << val << std::endl;
96 print_flags(f[i]);
97 std::cout << "Precision is: " << prec << std::endl;
98 std::cout << "Got: " << ss.str() << std::endl;
99 std::cout << "Expected: " << expect << std::endl;
100 ++boost::detail::test_errors();
101 mp_t(val).str(prec, f[i]); // for debugging
102 }
103 }
104 }
105 num = -num;
106 if(j & 1)
107 denom *= 8;
108 val = num / denom;
109 }
110
111 boost::array<const char*, 13 * 9> zeros =
112 {{ "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" }};
113
114 unsigned col = 0;
115 val = 0;
116 for(unsigned prec = 1; prec < 14; ++prec)
117 {
118 for(unsigned i = 0; i < f.size(); ++i, ++col)
119 {
120 std::stringstream ss;
121 ss.precision(prec);
122 ss.flags(f[i]);
123 ss << mp_t(val);
124 const char* expect = zeros[col];
125 if(ss.str() != expect)
126 {
127 std::cout << std::setprecision(20) << "Testing value " << val << std::endl;
128 print_flags(f[i]);
129 std::cout << "Precision is: " << prec << std::endl;
130 std::cout << "Got: " << ss.str() << std::endl;
131 std::cout << "Expected: " << expect << std::endl;
132 ++boost::detail::test_errors();
133 mp_t(val).str(prec, f[i]); // for debugging
134 }
135 }
136 }
137
138 if(std::numeric_limits<mp_t>::has_infinity)
139 {
140 T val = std::numeric_limits<T>::infinity();
141 BOOST_CHECK_EQUAL(val.str(), "inf");
142 BOOST_CHECK_EQUAL(val.str(0, std::ios_base::showpos), "+inf");
143 val = -val;
144 BOOST_CHECK_EQUAL(val.str(), "-inf");
145 BOOST_CHECK_EQUAL(val.str(0, std::ios_base::showpos), "-inf");
146
147 val = static_cast<T>("inf");
148 BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
149 val = static_cast<T>("+inf");
150 BOOST_CHECK_EQUAL(val, std::numeric_limits<T>::infinity());
151 val = static_cast<T>("-inf");
152 BOOST_CHECK_EQUAL(val, -std::numeric_limits<T>::infinity());
153 }
154 if(std::numeric_limits<mp_t>::has_quiet_NaN)
155 {
156 T val = std::numeric_limits<T>::quiet_NaN();
157 BOOST_CHECK_EQUAL(val.str(), "nan");
158 val = static_cast<T>("nan");
159 BOOST_CHECK((boost::math::isnan)(val));
160 }
161 //
162 // Min and max values:
163 //
164 T t((std::numeric_limits<T>::max)().str(std::numeric_limits<T>::max_digits10, std::ios_base::scientific));
165 BOOST_CHECK_EQUAL(t, (std::numeric_limits<T>::max)());
166 t = T((std::numeric_limits<T>::min)().str(std::numeric_limits<T>::max_digits10, std::ios_base::scientific));
167 BOOST_CHECK_EQUAL(t, (std::numeric_limits<T>::min)());
168 t = T((std::numeric_limits<T>::lowest)().str(std::numeric_limits<T>::max_digits10, std::ios_base::scientific));
169 BOOST_CHECK_EQUAL(t, (std::numeric_limits<T>::lowest)());
170 }
171
172 template <class T>
173 T generate_random()
174 {
175 typedef typename T::backend_type::exponent_type e_type;
176 static boost::random::mt19937 gen;
177 T val = gen();
178 T prev_val = -1;
179 while(val != prev_val)
180 {
181 val *= (gen.max)();
182 prev_val = val;
183 val += gen();
184 }
185 e_type e;
186 val = frexp(val, &e);
187
188 static boost::random::uniform_int_distribution<e_type> ui(0, std::numeric_limits<T>::max_exponent);
189 return ldexp(val, ui(gen));
190 }
191
192 template <class T>
193 void do_round_trip(const T& val, std::ios_base::fmtflags f)
194 {
195 std::stringstream ss;
196 #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS
197 ss << std::setprecision(std::numeric_limits<T>::max_digits10);
198 #else
199 ss << std::setprecision(std::numeric_limits<T>::digits10 + 3);
200 #endif
201 ss.flags(f);
202 ss << val;
203 T new_val = static_cast<T>(ss.str());
204 BOOST_CHECK_EQUAL(new_val, val);
205 new_val = static_cast<T>(val.str(0, f));
206 BOOST_CHECK_EQUAL(new_val, val);
207 }
208
209 template <class T>
210 void do_round_trip(const T& val)
211 {
212 do_round_trip(val, std::ios_base::fmtflags(0));
213 do_round_trip(val, std::ios_base::fmtflags(std::ios_base::scientific));
214 if((fabs(val) > 1) && (fabs(val) < 1e100))
215 do_round_trip(val, std::ios_base::fmtflags(std::ios_base::fixed));
216
217 static int error_count = 0;
218
219 if(error_count != boost::detail::test_errors())
220 {
221 error_count = boost::detail::test_errors();
222 std::cout << "Errors occured while testing value....";
223 if(val.backend().sign())
224 std::cout << "-";
225 std::cout << boost::multiprecision::cpp_int(val.backend().bits()) << "e" << val.backend().exponent() << std::endl;
226 }
227 }
228
229 template <class T>
230 void test_round_trip()
231 {
232 std::cout << "Testing type " << typeid(T).name() << std::endl;
233 std::cout << "digits = " << std::numeric_limits<T>::digits << std::endl;
234 std::cout << "digits10 = " << std::numeric_limits<T>::digits10 << std::endl;
235 std::cout << "max_digits10 = " << std::numeric_limits<T>::max_digits10 << std::endl;
236
237 stopwatch<boost::chrono::high_resolution_clock> w;
238
239 while(boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count() < 200)
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) break; // escape if there are too many errors.
248 }
249
250 std::cout << "Execution time = " << boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count() << "s" << std::endl;
251 }
252
253 #if !defined(TEST1) && !defined(TEST2)
254 # define TEST1
255 # define TEST2
256 #endif
257
258 int main()
259 {
260 using namespace boost::multiprecision;
261 #ifdef TEST1
262 test<number<cpp_bin_float<113, digit_base_2> > >();
263 test_round_trip<number<cpp_bin_float<113, digit_base_2> > >();
264 #endif
265 #ifdef TEST2
266 test<number<cpp_bin_float<53, digit_base_2> > >();
267 test_round_trip<number<cpp_bin_float<53, digit_base_2> > >();
268 #endif
269 return boost::report_errors();
270 }
271