debug_adaptor.hpp 26 KB

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