1 ///////////////////////////////////////////////////////////////
2 // Copyright 2017 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
5
6 #define BOOST_CHRONO_HEADER_ONLY
7
8 #ifdef _MSC_VER
9 # define _SCL_SECURE_NO_WARNINGS
10 #endif
11
12
13 #include "performance.hpp"
14 #include "table_helper.hpp"
15 #include <boost/random.hpp>
16 #include <boost/math/tools/polynomial.hpp>
17 #include <boost/multiprecision/cpp_int.hpp>
18
19 unsigned max_reps = 1000;
20
21 template <class T>
22 struct tester
23 {
testertester24 tester()
25 {
26 a.assign(500, T());
27 for(int i = 0; i < 500; ++i)
28 {
29 b.push_back(generate_random(false));
30 c.push_back(generate_random(false));
31 small.push_back(generate_random(true));
32 }
33 }
test_addtester34 double test_add()
35 {
36 stopwatch<boost::chrono::high_resolution_clock> w;
37 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
38 {
39 for(unsigned i = 0; i < b.size(); ++i)
40 a[i] = b[i] + c[i];
41 }
42 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
43 }
test_subtracttester44 double test_subtract()
45 {
46 stopwatch<boost::chrono::high_resolution_clock> w;
47 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
48 {
49 for(unsigned i = 0; i < b.size(); ++i)
50 a[i] = b[i] - c[i];
51 }
52 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
53 }
test_add_inttester54 double test_add_int()
55 {
56 stopwatch<boost::chrono::high_resolution_clock> w;
57 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
58 {
59 for(unsigned i = 0; i < b.size(); ++i)
60 a[i] = b[i] + 1;
61 }
62 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
63 }
test_subtract_inttester64 double test_subtract_int()
65 {
66 stopwatch<boost::chrono::high_resolution_clock> w;
67 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
68 {
69 for(unsigned i = 0; i < b.size(); ++i)
70 a[i] = b[i] - 1;
71 }
72 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
73 }
test_multiplytester74 double test_multiply()
75 {
76 stopwatch<boost::chrono::high_resolution_clock> w;
77 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
78 {
79 for(unsigned k = 0; k < b.size(); ++k)
80 a[k] = b[k] * c[k];
81 }
82 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
83 }
test_multiply_inttester84 double test_multiply_int()
85 {
86 stopwatch<boost::chrono::high_resolution_clock> w;
87 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
88 {
89 for(unsigned i = 0; i < b.size(); ++i)
90 a[i] = b[i] * 3;
91 }
92 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
93 }
test_dividetester94 double test_divide()
95 {
96 stopwatch<boost::chrono::high_resolution_clock> w;
97 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
98 {
99 for(unsigned i = 0; i < b.size(); ++i)
100 a[i] = b[i] / small[i];
101 }
102 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
103 }
test_divide_inttester104 double test_divide_int()
105 {
106 stopwatch<boost::chrono::high_resolution_clock> w;
107 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
108 {
109 for(unsigned i = 0; i < b.size(); ++i)
110 a[i] = b[i] / 3;
111 }
112 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
113 }
test_gcdtester114 double test_gcd()
115 {
116 using boost::integer::gcd;
117 stopwatch<boost::chrono::high_resolution_clock> w;
118 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
119 {
120 for(unsigned i = 0; i < b.size(); ++i)
121 a[i] = gcd(b[i], c[i]);
122 }
123 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
124 }
125
test_inplace_addtester126 double test_inplace_add()
127 {
128 stopwatch<boost::chrono::high_resolution_clock> w;
129 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
130 {
131 for (unsigned i = 0; i < b.size(); ++i)
132 b[i] += c[i];
133 }
134 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
135 }
test_inplace_subtracttester136 double test_inplace_subtract()
137 {
138 stopwatch<boost::chrono::high_resolution_clock> w;
139 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
140 {
141 for (unsigned i = 0; i < b.size(); ++i)
142 b[i] -= c[i];
143 }
144 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
145 }
test_inplace_add_inttester146 double test_inplace_add_int()
147 {
148 stopwatch<boost::chrono::high_resolution_clock> w;
149 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
150 {
151 for (unsigned i = 0; i < b.size(); ++i)
152 b[i] += 1;
153 }
154 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
155 }
test_inplace_subtract_inttester156 double test_inplace_subtract_int()
157 {
158 stopwatch<boost::chrono::high_resolution_clock> w;
159 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
160 {
161 for (unsigned i = 0; i < b.size(); ++i)
162 b[i] -= 1;
163 }
164 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
165 }
test_inplace_multiplytester166 double test_inplace_multiply()
167 {
168 stopwatch<boost::chrono::high_resolution_clock> w;
169 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
170 {
171 for (unsigned k = 0; k < b.size(); ++k)
172 b[k] *= c[k];
173 }
174 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
175 }
test_inplace_multiply_inttester176 double test_inplace_multiply_int()
177 {
178 stopwatch<boost::chrono::high_resolution_clock> w;
179 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
180 {
181 for (unsigned i = 0; i < b.size(); ++i)
182 b[i] *= 3;
183 }
184 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
185 }
test_inplace_dividetester186 double test_inplace_divide()
187 {
188 stopwatch<boost::chrono::high_resolution_clock> w;
189 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
190 {
191 for (unsigned i = 0; i < b.size(); ++i)
192 a[i] /= small[i];
193 }
194 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
195 }
test_inplace_divide_inttester196 double test_inplace_divide_int()
197 {
198 stopwatch<boost::chrono::high_resolution_clock> w;
199 for (unsigned repeats = 0; repeats < max_reps; ++repeats)
200 {
201 for (unsigned i = 0; i < b.size(); ++i)
202 b[i] /= 3;
203 }
204 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
205 }
206 private:
generate_randomtester207 T generate_random(bool issmall)
208 {
209 boost::uniform_int<> ui(2, issmall ? 5 : 40), ui2(1, 10000);
210 std::size_t len = ui(gen);
211 std::vector<typename T::value_type> values;
212 for (std::size_t i = 0; i < len; ++i)
213 {
214 values.push_back(static_cast<typename T::value_type>(ui2(gen)));
215 }
216 return T(values.begin(), values.end());
217 }
218 std::vector<T> a, b, c, small;
219 static boost::random::mt19937 gen;
220 };
221
222 template <class N>
223 boost::random::mt19937 tester<N>::gen;
224
225 template <class Number>
test(const char * type)226 void test(const char* type)
227 {
228 std::cout << "Testing type: " << type << std::endl;
229 tester<boost::math::tools::polynomial<Number> > t;
230 int count = 500 * max_reps;
231 std::string table_name = "Polynomial Arithmetic (" + compiler_name() + ", " + platform_name() + ")";
232 //
233 // Now the actual tests:
234 //
235 report_execution_time(t.test_add() / count, table_name, "operator +", type);
236 report_execution_time(t.test_subtract() / count, table_name, "operator -", type);
237 report_execution_time(t.test_multiply() / count, table_name, "operator *", type);
238 report_execution_time(t.test_divide() / count, table_name, "operator /", type);
239 report_execution_time(t.test_add_int() / count, table_name, "operator + (int)", type);
240 report_execution_time(t.test_subtract_int() / count, table_name, "operator - (int)", type);
241 report_execution_time(t.test_multiply_int() / count, table_name, "operator * (int)", type);
242 report_execution_time(t.test_divide_int() / count, table_name, "operator / (int)", type);
243 report_execution_time(t.test_inplace_add() / count, table_name, "operator +=", type);
244 report_execution_time(t.test_inplace_subtract() / count, table_name, "operator -=", type);
245 report_execution_time(t.test_inplace_multiply() / count, table_name, "operator *=", type);
246 report_execution_time(t.test_inplace_divide() / count, table_name, "operator /=", type);
247 report_execution_time(t.test_inplace_add_int() / count, table_name, "operator += (int)", type);
248 report_execution_time(t.test_inplace_subtract_int() / count, table_name, "operator -= (int)", type);
249 report_execution_time(t.test_inplace_multiply_int() / count, table_name, "operator *= (int)", type);
250 report_execution_time(t.test_inplace_divide_int() / count, table_name, "operator /= (int)", type);
251 //report_execution_time(t.test_gcd() / count, table_name, "gcd", type);
252 }
253
254
main()255 int main()
256 {
257 test<boost::uint64_t>("boost::uint64_t");
258 test<double>("double");
259 max_reps = 100;
260 test<boost::multiprecision::cpp_int>("cpp_int");
261 return 0;
262 }
263
264