Imported Upstream version 1.72.0
[platform/upstream/boost.git] / 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 }