]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
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 |