libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
fma.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2002 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "stdafx.h"
20 
21 #define BOOST_TEST_MODULE libjmmcg_tests
22 #include <boost/test/included/unit_test.hpp>
23 
24 #include <boost/mpl/list.hpp>
25 
26 #include "core/ave_deviation_meter.hpp"
27 #include "core/fma.hpp"
28 
29 #include <chrono>
30 
31 using namespace libjmmcg;
32 
33 BOOST_AUTO_TEST_SUITE(fma_tests)
34 
35 BOOST_AUTO_TEST_CASE(all_zero)
36 {
37  using namespace fma;
38 
39  const double m=0;
40  const double x=0;
41  const double c=0;
42  const double y=dbl(x)*m+c;
43  BOOST_CHECK_EQUAL(y, 0.0);
44 }
45 
46 BOOST_AUTO_TEST_CASE(all_zero_commute_multiply)
47 {
48  using namespace fma;
49 
50  const double m=3;
51  const double x=4;
52  const double c=5;
53  const double y=m*dbl(x)+c;
54  BOOST_CHECK_EQUAL(y, 17.0);
55 }
56 
57 BOOST_AUTO_TEST_CASE(all_zero_commute_add)
58 {
59  using namespace fma;
60 
61  const double m=3;
62  const double x=4;
63  const double c=5;
64  const double y=c+dbl(x)*m;
65  BOOST_CHECK_EQUAL(y, 17.0);
66 }
67 
68 BOOST_AUTO_TEST_CASE(all_zero_commute_multipy_and_add)
69 {
70  using namespace fma;
71 
72  const double m=3;
73  const double x=4;
74  const double c=5;
75  const double y=c+m*dbl(x);
76  BOOST_CHECK_EQUAL(y, 17.0);
77 }
78 
79 BOOST_AUTO_TEST_CASE(all_zero_nest)
80 {
81  using namespace fma;
82 
83  const double m=3;
84  const double x=4;
85  const double c=5;
86  const double y=dbl(dbl(x)*m+c)*m+c;
87  BOOST_CHECK_EQUAL(y, 56.0);
88 }
89 
90 BOOST_AUTO_TEST_CASE(m_one_others_zero)
91 {
92  using namespace fma;
93 
94  const double m=1;
95  const double x=0;
96  const double c=0;
97  const double y=dbl(x)*m+c;
98  BOOST_CHECK_EQUAL(y, 0.0);
99 }
100 
101 BOOST_AUTO_TEST_CASE(all_ones)
102 {
103  using namespace fma;
104 
105  const double m=1;
106  const double x=1;
107  const double c=1;
108  const double y=dbl(x)*m+c;
109  BOOST_CHECK_EQUAL(y, 2.0);
110 }
111 
112 BOOST_AUTO_TEST_CASE(one_two)
113 {
114  using namespace fma;
115 
116  const double m=1;
117  const double x=2;
118  const double c=1;
119  const double y=dbl(x)*m+c;
120  BOOST_CHECK_EQUAL(y, 3.0);
121 }
122 
123 BOOST_AUTO_TEST_CASE(all_twos)
124 {
125  using namespace fma;
126 
127  const double m=2;
128  const double x=2;
129  const double c=2;
130  const double y=dbl(x)*m+c;
131  BOOST_CHECK_EQUAL(y, 6.0);
132 }
133 
134 BOOST_AUTO_TEST_CASE(subtract_twos)
135 {
136  using namespace fma;
137 
138  const double m=2;
139  const double x=2;
140  const double c=2;
141  const double y=dbl(x)*m-c;
142  BOOST_CHECK_EQUAL(y, 2.0);
143 }
144 
145 BOOST_AUTO_TEST_CASE(associative_subtract_twos)
146 {
147  using namespace fma;
148 
149  const double m=2;
150  const double x=2;
151  const double c=2;
152  const double y=c-dbl(x)*m;
153  BOOST_CHECK_EQUAL(y, -2.0);
154 }
155 
156 BOOST_AUTO_TEST_CASE(all_zero_two_surrounding_multiplies)
157 {
158  using namespace fma;
159 
160  const double m=3;
161  const double x=4;
162  const double c=5;
163  const double y=m*dbl(x)*m+c;
164  BOOST_CHECK_EQUAL(y, 41.0);
165 }
166 
167 BOOST_AUTO_TEST_CASE(all_zero_two_post_multiplies)
168 {
169  using namespace fma;
170 
171  const double m=3;
172  const double x=4;
173  const double c=5;
174  const double y=dbl(x)*m*m+c;
175  BOOST_CHECK_EQUAL(y, 41.0);
176 }
177 
178 BOOST_AUTO_TEST_CASE(all_zero_two_preceeding_multiplies)
179 {
180  using namespace fma;
181 
182  const double m=3;
183  const double x=4;
184  const double c=5;
185  const double y=m*m*dbl(x)+c;
186  BOOST_CHECK_EQUAL(y, 41.0);
187 }
188 
189 BOOST_AUTO_TEST_CASE(all_zero_two_dbls_add)
190 {
191  using namespace fma;
192 
193  const dbl m=3;
194  const double x=4;
195  const dbl c=5;
196  const dbl y=m*m*dbl(x)+c;
197  BOOST_CHECK_EQUAL(y, 41.0);
198 }
199 
200 BOOST_AUTO_TEST_CASE(all_zero_two_dbls_subtract)
201 {
202  using namespace fma;
203 
204  const dbl m=3;
205  const double x=4;
206  const dbl c=5;
207  const dbl y=m*m*dbl(x)-c;
208  BOOST_CHECK_EQUAL(y, 31.0);
209 }
210 
211 BOOST_AUTO_TEST_CASE(all_zero_two_dbls_associative_add)
212 {
213  using namespace fma;
214 
215  const dbl m=2;
216  const double x=3;
217  const dbl c=4;
218  const dbl y=c+m*m*dbl(x);
219  BOOST_CHECK_EQUAL(y, 16.0);
220 }
221 
222 BOOST_AUTO_TEST_CASE(all_zero_two_dbls_associative_subtract)
223 {
224  using namespace fma;
225 
226  const dbl m=3;
227  const double x=4;
228  const dbl c=5;
229  const dbl y=c-m*m*dbl(x);
230  BOOST_CHECK_EQUAL(y, -31.0);
231 }
232 
233 BOOST_AUTO_TEST_CASE(multiply_equals_add)
234 {
235  using namespace fma;
236 
237  const double m=3;
238  const double c=5;
239  double y=4;
240  y*=dbl(m)+c;
241  BOOST_CHECK_EQUAL(y, 17.0);
242 }
243 
244 BOOST_AUTO_TEST_CASE(multiply_equals_subtract)
245 {
246  using namespace fma;
247 
248  const double m=3;
249  const double c=5;
250  double y=4;
251  y*=dbl(m)-c;
252  BOOST_CHECK_EQUAL(y, 7.0);
253 }
254 
255 BOOST_AUTO_TEST_CASE(add_equals)
256 {
257  using namespace fma;
258 
259  const double m=3;
260  const double x=4;
261  double y=5;
262  y+=x*dbl(m);
263  BOOST_CHECK_EQUAL(y, 17.0);
264 }
265 
266 BOOST_AUTO_TEST_CASE(subtract_equals)
267 {
268  using namespace fma;
269 
270  const double m=3;
271  const double x=4;
272  double y=5;
273  y-=x*dbl(m);
274  BOOST_CHECK_EQUAL(y, 7.0);
275 }
276 
277 typedef boost::mpl::list<
278  double,
279  fma::dbl
281 
282 BOOST_AUTO_TEST_CASE_TEMPLATE(performance_all_zero_commute_multiply, T, check_fma_tests)
283 {
284  using timed_results_t=ave_deviation_meter<double>;
285 
286 #ifdef JMMCG_PERFORMANCE_TESTS
287  const unsigned long test_size=2<<19;
288  const unsigned long num_reps=10000;
289 #else
290  const unsigned long test_size=2<<2;
291  const unsigned long num_reps=2;
292 #endif
293 
294  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
295  0.1,
296  num_reps,
297  []() {
298  const double m=3;
299  const double x=4;
300  const double c=5;
301  double y=0;
302  const auto t1=std::chrono::high_resolution_clock::now();
303  for (unsigned long num_loops=0;num_loops<test_size;++num_loops) {
304  y+=m*T(x)+c;
305  }
306  const auto t2=std::chrono::high_resolution_clock::now();
307  BOOST_CHECK_EQUAL(y, test_size*17.0);
308  return timed_results_t::value_type(std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count())/test_size;
309  }
310  ));
311  std::cout<<"Time per "<<typeid(T).name()<<" operation: "<<timed_results.first<<" nanosec."<<std::endl;
312 #ifdef JMMCG_PERFORMANCE_TESTS
313  BOOST_CHECK(!timed_results.second);
314 #endif
315 }
316 
317 BOOST_AUTO_TEST_SUITE_END()