1///////////////////////////////////////////////////////////////
2// Copyright 2012 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#ifndef BOOST_MATH_LOGGED_ADAPTER_HPP
7#define BOOST_MATH_LOGGED_ADAPTER_HPP
8
9#include <boost/multiprecision/traits/extract_exponent_type.hpp>
10#include <boost/multiprecision/detail/integer_ops.hpp>
11
12namespace boost{
13namespace multiprecision{
14
15template <class Backend>
16inline void log_postfix_event(const Backend&, const char* /*event_description*/)
17{
18}
19template <class Backend, class T>
20inline void log_postfix_event(const Backend&, const T&, const char* /*event_description*/)
21{
22}
23template <class Backend>
24inline void log_prefix_event(const Backend&, const char* /*event_description*/)
25{
26}
27template <class Backend, class T>
28inline void log_prefix_event(const Backend&, const T&, const char* /*event_description*/)
29{
30}
31template <class Backend, class T, class U>
32inline void log_prefix_event(const Backend&, const T&, const U&, const char* /*event_description*/)
33{
34}
35template <class Backend, class T, class U, class V>
36inline void log_prefix_event(const Backend&, const T&, const U&, const V&, const char* /*event_description*/)
37{
38}
39
40namespace backends{
41
42template <class Backend>
43struct logged_adaptor
44{
45 typedef typename Backend::signed_types signed_types;
46 typedef typename Backend::unsigned_types unsigned_types;
47 typedef typename Backend::float_types float_types;
48 typedef typename extract_exponent_type<
49 Backend, number_category<Backend>::value>::type exponent_type;
50
51private:
52
53 Backend m_value;
54public:
55 logged_adaptor()
56 {
57 log_postfix_event(m_value, "Default construct");
58 }
59 logged_adaptor(const logged_adaptor& o)
60 {
61 log_prefix_event(m_value, o.value(), "Copy construct");
62 m_value = o.m_value;
63 log_postfix_event(m_value, "Copy construct");
64 }
65 logged_adaptor& operator = (const logged_adaptor& o)
66 {
67 log_prefix_event(m_value, o.value(), "Assignment");
68 m_value = o.m_value;
69 log_postfix_event(m_value, "Copy construct");
70 return *this;
71 }
72 template <class T>
73 logged_adaptor(const T& i, const typename enable_if_c<is_convertible<T, Backend>::value>::type* = 0)
74 : m_value(i)
75 {
76 log_postfix_event(m_value, "construct from arithmetic type");
77 }
78 template <class T>
79 typename enable_if_c<is_arithmetic<T>::value || is_convertible<T, Backend>::value, logged_adaptor&>::type operator = (const T& i)
80 {
81 log_prefix_event(m_value, i, "Assignment from arithmetic type");
82 m_value = i;
83 log_postfix_event(m_value, "Assignment from arithmetic type");
84 return *this;
85 }
86 logged_adaptor& operator = (const char* s)
87 {
88 log_prefix_event(m_value, s, "Assignment from string type");
89 m_value = s;
90 log_postfix_event(m_value, "Assignment from string type");
91 return *this;
92 }
93 void swap(logged_adaptor& o)
94 {
95 log_prefix_event(m_value, o.value(), "swap");
96 std::swap(m_value, o.value());
97 log_postfix_event(m_value, "swap");
98 }
99 std::string str(std::streamsize digits, std::ios_base::fmtflags f)const
100 {
101 log_prefix_event(m_value, "Conversion to string");
102 std::string s = m_value.str(digits, f);
103 log_postfix_event(m_value, s, "Conversion to string");
104 return s;
105 }
106 void negate()
107 {
108 log_prefix_event(m_value, "negate");
109 m_value.negate();
110 log_postfix_event(m_value, "negate");
111 }
112 int compare(const logged_adaptor& o)const
113 {
114 log_prefix_event(m_value, o.value(), "compare");
115 int r = m_value.compare(o.value());
116 log_postfix_event(m_value, r, "compare");
117 return r;
118 }
119 template <class T>
120 int compare(const T& i)const
121 {
122 log_prefix_event(m_value, i, "compare");
123 int r = m_value.compare(i);
124 log_postfix_event(m_value, r, "compare");
125 return r;
126 }
127 Backend& value()
128 {
129 return m_value;
130 }
131 const Backend& value()const
132 {
133 return m_value;
134 }
135 template <class Archive>
136 void serialize(Archive& ar, const unsigned int /*version*/)
137 {
138 log_prefix_event(m_value, "serialize");
139 ar & m_value;
140 log_postfix_event(m_value, "serialize");
141 }
142};
143
144template <class T>
145inline const T& unwrap_logged_type(const T& a) { return a; }
146template <class Backend>
147inline const Backend& unwrap_logged_type(const logged_adaptor<Backend>& a) { return a.value(); }
148
149#define NON_MEMBER_OP1(name, str) \
150 template <class Backend>\
151 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result)\
152 {\
153 using default_ops::BOOST_JOIN(eval_, name);\
154 log_prefix_event(result.value(), str);\
155 BOOST_JOIN(eval_, name)(result.value());\
156 log_postfix_event(result.value(), str);\
157 }
158
159#define NON_MEMBER_OP2(name, str) \
160 template <class Backend, class T>\
161 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a)\
162 {\
163 using default_ops::BOOST_JOIN(eval_, name);\
164 log_prefix_event(result.value(), unwrap_logged_type(a), str);\
165 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a));\
166 log_postfix_event(result.value(), str);\
167 }\
168 template <class Backend>\
169 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a)\
170 {\
171 using default_ops::BOOST_JOIN(eval_, name);\
172 log_prefix_event(result.value(), unwrap_logged_type(a), str);\
173 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a));\
174 log_postfix_event(result.value(), str);\
175 }
176
177#define NON_MEMBER_OP3(name, str) \
178 template <class Backend, class T, class U>\
179 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const U& b)\
180 {\
181 using default_ops::BOOST_JOIN(eval_, name);\
182 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
183 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
184 log_postfix_event(result.value(), str);\
185 }\
186 template <class Backend, class T>\
187 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const T& b)\
188 {\
189 using default_ops::BOOST_JOIN(eval_, name);\
190 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
191 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
192 log_postfix_event(result.value(), str);\
193 }\
194 template <class Backend, class T>\
195 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const logged_adaptor<Backend>& b)\
196 {\
197 using default_ops::BOOST_JOIN(eval_, name);\
198 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
199 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
200 log_postfix_event(result.value(), str);\
201 }\
202 template <class Backend>\
203 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b)\
204 {\
205 using default_ops::BOOST_JOIN(eval_, name);\
206 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), str);\
207 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b));\
208 log_postfix_event(result.value(), str);\
209 }
210
211#define NON_MEMBER_OP4(name, str) \
212 template <class Backend, class T, class U, class V>\
213 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const U& b, const V& c)\
214 {\
215 using default_ops::BOOST_JOIN(eval_, name);\
216 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
217 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
218 log_postfix_event(result.value(), str);\
219 }\
220 template <class Backend, class T>\
221 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b, const T& c)\
222 {\
223 using default_ops::BOOST_JOIN(eval_, name);\
224 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
225 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
226 log_postfix_event(result.value(), str);\
227 }\
228 template <class Backend, class T>\
229 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const T& b, const logged_adaptor<Backend>& c)\
230 {\
231 using default_ops::BOOST_JOIN(eval_, name);\
232 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
233 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
234 log_postfix_event(result.value(), str);\
235 }\
236 template <class Backend, class T>\
237 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const T& a, const logged_adaptor<Backend>& b, const logged_adaptor<Backend>& c)\
238 {\
239 using default_ops::BOOST_JOIN(eval_, name);\
240 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
241 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
242 log_postfix_event(result.value(), str);\
243 }\
244 template <class Backend>\
245 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const logged_adaptor<Backend>& b, const logged_adaptor<Backend>& c)\
246 {\
247 using default_ops::BOOST_JOIN(eval_, name);\
248 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
249 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
250 log_postfix_event(result.value(), str);\
251 }\
252 template <class Backend, class T, class U>\
253 inline void BOOST_JOIN(eval_, name)(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& a, const T& b, const U& c)\
254 {\
255 using default_ops::BOOST_JOIN(eval_, name);\
256 log_prefix_event(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c), str);\
257 BOOST_JOIN(eval_, name)(result.value(), unwrap_logged_type(a), unwrap_logged_type(b), unwrap_logged_type(c));\
258 log_postfix_event(result.value(), str);\
259 }\
260
261NON_MEMBER_OP2(add, "+=");
262NON_MEMBER_OP2(subtract, "-=");
263NON_MEMBER_OP2(multiply, "*=");
264NON_MEMBER_OP2(divide, "/=");
265
266template <class Backend, class R>
267inline void eval_convert_to(R* result, const logged_adaptor<Backend>& val)
268{
269 using default_ops::eval_convert_to;
270 log_prefix_event(val.value(), "convert_to");
271 eval_convert_to(result, val.value());
272 log_postfix_event(val.value(), *result, "convert_to");
273}
274
275template <class Backend, class Exp>
276inline void eval_frexp(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp* exp)
277{
278 log_prefix_event(arg.value(), "frexp");
279 eval_frexp(result.value(), arg.value(), exp);
280 log_postfix_event(result.value(), *exp, "frexp");
281}
282
283template <class Backend, class Exp>
284inline void eval_ldexp(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp exp)
285{
286 log_prefix_event(arg.value(), "ldexp");
287 eval_ldexp(result.value(), arg.value(), exp);
288 log_postfix_event(result.value(), exp, "ldexp");
289}
290
291template <class Backend, class Exp>
292inline void eval_scalbn(logged_adaptor<Backend>& result, const logged_adaptor<Backend>& arg, Exp exp)
293{
294 log_prefix_event(arg.value(), "scalbn");
295 eval_scalbn(result.value(), arg.value(), exp);
296 log_postfix_event(result.value(), exp, "scalbn");
297}
298
299template <class Backend>
300inline typename Backend::exponent_type eval_ilogb(const logged_adaptor<Backend>& arg)
301{
302 log_prefix_event(arg.value(), "ilogb");
303 typename Backend::exponent_type r = eval_ilogb(arg.value());
304 log_postfix_event(arg.value(), "ilogb");
305 return r;
306}
307
308NON_MEMBER_OP2(floor, "floor");
309NON_MEMBER_OP2(ceil, "ceil");
310NON_MEMBER_OP2(sqrt, "sqrt");
311
312template <class Backend>
313inline int eval_fpclassify(const logged_adaptor<Backend>& arg)
314{
315 using default_ops::eval_fpclassify;
316 log_prefix_event(arg.value(), "fpclassify");
317 int r = eval_fpclassify(arg.value());
318 log_postfix_event(arg.value(), r, "fpclassify");
319 return r;
320}
321
322/*********************************************************************
323*
324* Optional arithmetic operations come next:
325*
326*********************************************************************/
327
328NON_MEMBER_OP3(add, "+");
329NON_MEMBER_OP3(subtract, "-");
330NON_MEMBER_OP3(multiply, "*");
331NON_MEMBER_OP3(divide, "/");
332NON_MEMBER_OP3(multiply_add, "fused-multiply-add");
333NON_MEMBER_OP3(multiply_subtract, "fused-multiply-subtract");
334NON_MEMBER_OP4(multiply_add, "fused-multiply-add");
335NON_MEMBER_OP4(multiply_subtract, "fused-multiply-subtract");
336
337NON_MEMBER_OP1(increment, "increment");
338NON_MEMBER_OP1(decrement, "decrement");
339
340/*********************************************************************
341*
342* Optional integer operations come next:
343*
344*********************************************************************/
345
346NON_MEMBER_OP2(modulus, "%=");
347NON_MEMBER_OP3(modulus, "%");
348NON_MEMBER_OP2(bitwise_or, "|=");
349NON_MEMBER_OP3(bitwise_or, "|");
350NON_MEMBER_OP2(bitwise_and, "&=");
351NON_MEMBER_OP3(bitwise_and, "&");
352NON_MEMBER_OP2(bitwise_xor, "^=");
353NON_MEMBER_OP3(bitwise_xor, "^");
354NON_MEMBER_OP4(qr, "quotient-and-remainder");
355NON_MEMBER_OP2(complement, "~");
356
357template <class Backend>
358inline void eval_left_shift(logged_adaptor<Backend>& arg, unsigned a)
359{
360 using default_ops::eval_left_shift;
361 log_prefix_event(arg.value(), a, "<<=");
362 eval_left_shift(arg.value(), a);
363 log_postfix_event(arg.value(), "<<=");
364}
365template <class Backend>
366inline void eval_left_shift(logged_adaptor<Backend>& arg, const logged_adaptor<Backend>& a, unsigned b)
367{
368 using default_ops::eval_left_shift;
369 log_prefix_event(arg.value(), a, b, "<<");
370 eval_left_shift(arg.value(), a.value(), b);
371 log_postfix_event(arg.value(), "<<");
372}
373template <class Backend>
374inline void eval_right_shift(logged_adaptor<Backend>& arg, unsigned a)
375{
376 using default_ops::eval_right_shift;
377 log_prefix_event(arg.value(), a, ">>=");
378 eval_right_shift(arg.value(), a);
379 log_postfix_event(arg.value(), ">>=");
380}
381template <class Backend>
382inline void eval_right_shift(logged_adaptor<Backend>& arg, const logged_adaptor<Backend>& a, unsigned b)
383{
384 using default_ops::eval_right_shift;
385 log_prefix_event(arg.value(), a, b, ">>");
386 eval_right_shift(arg.value(), a.value(), b);
387 log_postfix_event(arg.value(), ">>");
388}
389
390template <class Backend, class T>
391inline unsigned eval_integer_modulus(const logged_adaptor<Backend>& arg, const T& a)
392{
393 using default_ops::eval_integer_modulus;
394 log_prefix_event(arg.value(), a, "integer-modulus");
395 unsigned r = eval_integer_modulus(arg.value(), a);
396 log_postfix_event(arg.value(), r, "integer-modulus");
397 return r;
398}
399
400template <class Backend>
401inline unsigned eval_lsb(const logged_adaptor<Backend>& arg)
402{
403 using default_ops::eval_lsb;
404 log_prefix_event(arg.value(), "least-significant-bit");
405 unsigned r = eval_lsb(arg.value());
406 log_postfix_event(arg.value(), r, "least-significant-bit");
407 return r;
408}
409
410template <class Backend>
411inline unsigned eval_msb(const logged_adaptor<Backend>& arg)
412{
413 using default_ops::eval_msb;
414 log_prefix_event(arg.value(), "most-significant-bit");
415 unsigned r = eval_msb(arg.value());
416 log_postfix_event(arg.value(), r, "most-significant-bit");
417 return r;
418}
419
420template <class Backend>
421inline bool eval_bit_test(const logged_adaptor<Backend>& arg, unsigned a)
422{
423 using default_ops::eval_bit_test;
424 log_prefix_event(arg.value(), a, "bit-test");
425 bool r = eval_bit_test(arg.value(), a);
426 log_postfix_event(arg.value(), r, "bit-test");
427 return r;
428}
429
430template <class Backend>
431inline void eval_bit_set(const logged_adaptor<Backend>& arg, unsigned a)
432{
433 using default_ops::eval_bit_set;
434 log_prefix_event(arg.value(), a, "bit-set");
435 eval_bit_set(arg.value(), a);
436 log_postfix_event(arg.value(), arg, "bit-set");
437}
438template <class Backend>
439inline void eval_bit_unset(const logged_adaptor<Backend>& arg, unsigned a)
440{
441 using default_ops::eval_bit_unset;
442 log_prefix_event(arg.value(), a, "bit-unset");
443 eval_bit_unset(arg.value(), a);
444 log_postfix_event(arg.value(), arg, "bit-unset");
445}
446template <class Backend>
447inline void eval_bit_flip(const logged_adaptor<Backend>& arg, unsigned a)
448{
449 using default_ops::eval_bit_flip;
450 log_prefix_event(arg.value(), a, "bit-flip");
451 eval_bit_flip(arg.value(), a);
452 log_postfix_event(arg.value(), arg, "bit-flip");
453}
454
455NON_MEMBER_OP3(gcd, "gcd");
456NON_MEMBER_OP3(lcm, "lcm");
457NON_MEMBER_OP4(powm, "powm");
458
459/*********************************************************************
460*
461* abs/fabs:
462*
463*********************************************************************/
464
465NON_MEMBER_OP2(abs, "abs");
466NON_MEMBER_OP2(fabs, "fabs");
467
468/*********************************************************************
469*
470* Floating point functions:
471*
472*********************************************************************/
473
474NON_MEMBER_OP2(trunc, "trunc");
475NON_MEMBER_OP2(round, "round");
476NON_MEMBER_OP2(exp, "exp");
477NON_MEMBER_OP2(log, "log");
478NON_MEMBER_OP2(log10, "log10");
479NON_MEMBER_OP2(sin, "sin");
480NON_MEMBER_OP2(cos, "cos");
481NON_MEMBER_OP2(tan, "tan");
482NON_MEMBER_OP2(asin, "asin");
483NON_MEMBER_OP2(acos, "acos");
484NON_MEMBER_OP2(atan, "atan");
485NON_MEMBER_OP2(sinh, "sinh");
486NON_MEMBER_OP2(cosh, "cosh");
487NON_MEMBER_OP2(tanh, "tanh");
488NON_MEMBER_OP2(logb, "logb");
489NON_MEMBER_OP3(fmod, "fmod");
490NON_MEMBER_OP3(pow, "pow");
491NON_MEMBER_OP3(atan2, "atan2");
492
493} // namespace backends
494
495using backends::logged_adaptor;
496
497template<class Backend>
498struct number_category<backends::logged_adaptor<Backend> > : public number_category<Backend> {};
499
500}} // namespaces
501
502namespace std{
503
504template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates>
505class numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<Backend>, ExpressionTemplates> >
506 : public std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> >
507{
508 typedef std::numeric_limits<boost::multiprecision::number<Backend, ExpressionTemplates> > base_type;
509 typedef boost::multiprecision::number<boost::multiprecision::backends::logged_adaptor<Backend>, ExpressionTemplates> number_type;
510public:
511 static number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); }
512 static number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); }
513 static number_type lowest() BOOST_NOEXCEPT { return -(max)(); }
514 static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); }
515 static number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; }
516 static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); }
517 static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); }
518 static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); }
519 static number_type denorm_min() BOOST_NOEXCEPT { return base_type::denorm_min(); }
520};
521
522} // namespace std
523
524namespace boost{ namespace math{
525
526namespace policies{
527
528template <class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Policy>
529struct precision< boost::multiprecision::number<boost::multiprecision::logged_adaptor<Backend>, ExpressionTemplates>, Policy>
530 : public precision<boost::multiprecision::number<Backend, ExpressionTemplates>, Policy>
531{};
532
533} // namespace policies
534
535}} // namespaces boost::math
536
537#undef NON_MEMBER_OP1
538#undef NON_MEMBER_OP2
539#undef NON_MEMBER_OP3
540#undef NON_MEMBER_OP4
541
542#endif
543

source code of boost/boost/multiprecision/logged_adaptor.hpp