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