Ticket #12527: cpp_bin_float_conversion_performance.cpp

File cpp_bin_float_conversion_performance.cpp, 3.9 KB (added by John Maddock, 6 years ago)
Line 
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
7template <class Clock>
8struct 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
24private:
25 typename Clock::time_point m_start;
26};
27
28template <class T>
29T 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
49template <typename T>
50double 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
99template <class T>
100void 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
140int 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