Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / multiprecision / performance / cpp_bin_float_conversion_performance.cpp
1 //  Copyright 2018 John Maddock. Distributed under the Boost
2 //  Software License, Version 1.0. (See accompanying file
3 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5 #include <boost/multiprecision/cpp_bin_float.hpp>
6 #include <boost/math/special_functions.hpp>
7 #include <boost/chrono.hpp>
8 #include <boost/random/mersenne_twister.hpp>
9 #include <boost/random/uniform_int.hpp>
10
11 template <class Clock>
12 struct stopwatch
13 {
14    typedef typename Clock::duration duration;
15    stopwatch()
16    {
17       m_start = Clock::now();
18    }
19    duration elapsed()
20    {
21       return Clock::now() - m_start;
22    }
23    void reset()
24    {
25       m_start = Clock::now();
26    }
27
28  private:
29    typename Clock::time_point m_start;
30 };
31
32 template <class T>
33 T generate_random()
34 {
35    typedef int                   e_type;
36    static boost::random::mt19937 gen;
37    T                             val      = gen();
38    T                             prev_val = -1;
39    while (val != prev_val)
40    {
41       val *= (gen.max)();
42       prev_val = val;
43       val += gen();
44    }
45    e_type e;
46    val = frexp(val, &e);
47
48    static boost::random::uniform_int_distribution<e_type> ui(-20, 20);
49    return ldexp(val, ui(gen));
50 }
51
52 template <typename T>
53 double my_convert_to_double(const T& x)
54 {
55    double ret = 0;
56    if (isfinite(x))
57    {
58       if (x.backend().exponent() >= -1023 - 52 && x != 0)
59       {
60          if (x.backend().exponent() <= 1023)
61          {
62             int     e  = x.backend().exponent();
63             T       y  = ldexp(abs(x), 55 - e);
64             T       t  = trunc(y);
65             int64_t ti = t.template convert_to<int64_t>();
66             if ((ti & 1) == 0)
67             {
68                if (t < y)
69                   ti |= 1;
70             }
71             if (e >= -1023 + 1)
72             {
73                ret = ldexp(double(ti), e - 55);
74             }
75             else
76             {
77                // subnormal
78                typedef boost::multiprecision::number<boost::multiprecision::cpp_bin_float<128, boost::multiprecision::backends::digit_base_2> > cpp_bin_float128_t;
79                cpp_bin_float128_t                                                                                                               sx = ldexp(cpp_bin_float128_t(ti), e - 55);
80                sx += DBL_MIN;
81                e                     = -1023 + 1;
82                cpp_bin_float128_t sy = ldexp(sx, 55 - e);
83                cpp_bin_float128_t st = trunc(sy);
84                ti                    = st.convert_to<int64_t>();
85                if ((ti & 1) == 0)
86                {
87                   if (st < sy)
88                      ti |= 1;
89                }
90                ret = ldexp(double(ti), e - 55) - DBL_MIN;
91             }
92          }
93          else
94          {
95             // overflow
96             ret = HUGE_VAL;
97          }
98       }
99    }
100    else
101    {
102       if (isnan(x))
103          return nan("");
104       // inf
105       ret = HUGE_VAL;
106    }
107    return x.backend().sign() ? -ret : ret;
108 }
109
110 template <class T>
111 void test_conversion_time(const char* name)
112 {
113    std::cout << "Testing times for type: " << name << "\n";
114    std::vector<T> values;
115
116    for (unsigned i = 0; i < 10000000; ++i)
117    {
118       values.push_back(generate_random<T>());
119    }
120
121    boost::chrono::duration<double>                 time;
122    stopwatch<boost::chrono::high_resolution_clock> c;
123
124    double total = 0;
125
126    for (typename std::vector<T>::const_iterator i = values.begin(); i != values.end(); ++i)
127    {
128       total += my_convert_to_double(*i);
129    }
130
131    time = c.elapsed();
132    std::cout << std::setprecision(3) << std::fixed;
133    std::cout << "Reference time: " << std::setw(7) << std::right << time << " (total sum = " << total << ")" << std::endl;
134
135    c.reset();
136
137    total = 0;
138
139    for (typename std::vector<T>::const_iterator i = values.begin(); i != values.end(); ++i)
140    {
141       total += i->template convert_to<double>();
142    }
143
144    time = c.elapsed();
145    std::cout << "Boost time:     " << std::setw(7) << std::right << time << " (total sum = " << total << ")" << std::endl;
146 }
147
148 int main()
149 {
150    using namespace boost::multiprecision;
151
152    test_conversion_time<cpp_bin_float_double>("cpp_bin_float_double");
153    test_conversion_time<cpp_bin_float_quad>("cpp_bin_float_quad");
154    test_conversion_time<cpp_bin_float_oct>("cpp_bin_float_oct");
155    test_conversion_time<cpp_bin_float_50>("cpp_bin_float_50");
156    test_conversion_time<cpp_bin_float_100>("cpp_bin_float_100");
157
158    return 0;
159 }