debug_adaptor.hpp 26 KB

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