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 |
|
---|