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