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: |
29 | 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 | } |
42 | debug_adaptor() |
43 | { |
44 | update_view(); |
45 | } |
46 | debug_adaptor(const debug_adaptor& o) : debug_value(o.debug_value), m_value(o.m_value) |
47 | { |
48 | } |
49 | 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> |
56 | 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> |
62 | debug_adaptor(const T& i, const T& j) |
63 | : m_value(i, j) |
64 | { |
65 | update_view(); |
66 | } |
67 | template <class T> |
68 | 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 | } |
74 | debug_adaptor& operator = (const char* s) |
75 | { |
76 | m_value = s; |
77 | update_view(); |
78 | return *this; |
79 | } |
80 | void swap(debug_adaptor& o) |
81 | { |
82 | std::swap(m_value, o.value()); |
83 | std::swap(debug_value, o.debug_value); |
84 | } |
85 | std::string str(std::streamsize digits, std::ios_base::fmtflags f)const |
86 | { |
87 | return m_value.str(digits, f); |
88 | } |
89 | void negate() |
90 | { |
91 | m_value.negate(); |
92 | update_view(); |
93 | } |
94 | int compare(const debug_adaptor& o)const |
95 | { |
96 | return m_value.compare(o.value()); |
97 | } |
98 | template <class T> |
99 | int compare(const T& i)const |
100 | { |
101 | return m_value.compare(i); |
102 | } |
103 | Backend& value() |
104 | { |
105 | return m_value; |
106 | } |
107 | const Backend& value()const |
108 | { |
109 | return m_value; |
110 | } |
111 | template <class Archive> |
112 | 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> |
122 | inline Backend const& unwrap_debug_type(debug_adaptor<Backend> const& val) |
123 | { |
124 | return val.value(); |
125 | } |
126 | template <class T> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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> |
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: |
451 | static number_type (min)() BOOST_NOEXCEPT { return (base_type::min)(); } |
452 | static number_type (max)() BOOST_NOEXCEPT { return (base_type::max)(); } |
453 | static number_type lowest() BOOST_NOEXCEPT { return -(max)(); } |
454 | static number_type epsilon() BOOST_NOEXCEPT { return base_type::epsilon(); } |
455 | static number_type round_error() BOOST_NOEXCEPT { return epsilon() / 2; } |
456 | static number_type infinity() BOOST_NOEXCEPT { return base_type::infinity(); } |
457 | static number_type quiet_NaN() BOOST_NOEXCEPT { return base_type::quiet_NaN(); } |
458 | static number_type signaling_NaN() BOOST_NOEXCEPT { return base_type::signaling_NaN(); } |
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 | |