tommath.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2011 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_0.txt)
  5. #ifndef BOOST_MATH_MP_TOMMATH_BACKEND_HPP
  6. #define BOOST_MATH_MP_TOMMATH_BACKEND_HPP
  7. #include <boost/multiprecision/number.hpp>
  8. #include <boost/multiprecision/rational_adaptor.hpp>
  9. #include <boost/multiprecision/detail/integer_ops.hpp>
  10. #include <boost/math/special_functions/fpclassify.hpp>
  11. #include <boost/cstdint.hpp>
  12. #include <boost/scoped_array.hpp>
  13. #include <boost/functional/hash_fwd.hpp>
  14. #include <tommath.h>
  15. #include <cctype>
  16. #include <cmath>
  17. #include <limits>
  18. #include <climits>
  19. namespace boost { namespace multiprecision {
  20. namespace backends {
  21. namespace detail {
  22. inline void check_tommath_result(unsigned v)
  23. {
  24. if (v != MP_OKAY)
  25. {
  26. BOOST_THROW_EXCEPTION(std::runtime_error(mp_error_to_string(v)));
  27. }
  28. }
  29. } // namespace detail
  30. struct tommath_int;
  31. void eval_multiply(tommath_int& t, const tommath_int& o);
  32. void eval_add(tommath_int& t, const tommath_int& o);
  33. struct tommath_int
  34. {
  35. typedef mpl::list<boost::int32_t, boost::long_long_type> signed_types;
  36. typedef mpl::list<boost::uint32_t, boost::ulong_long_type> unsigned_types;
  37. typedef mpl::list<long double> float_types;
  38. tommath_int()
  39. {
  40. detail::check_tommath_result(mp_init(&m_data));
  41. }
  42. tommath_int(const tommath_int& o)
  43. {
  44. detail::check_tommath_result(mp_init_copy(&m_data, const_cast< ::mp_int*>(&o.m_data)));
  45. }
  46. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  47. tommath_int(tommath_int&& o) BOOST_NOEXCEPT
  48. {
  49. m_data = o.m_data;
  50. o.m_data.dp = 0;
  51. }
  52. tommath_int& operator=(tommath_int&& o)
  53. {
  54. mp_exch(&m_data, &o.m_data);
  55. return *this;
  56. }
  57. #endif
  58. tommath_int& operator=(const tommath_int& o)
  59. {
  60. if (m_data.dp == 0)
  61. detail::check_tommath_result(mp_init(&m_data));
  62. if (o.m_data.dp)
  63. detail::check_tommath_result(mp_copy(const_cast< ::mp_int*>(&o.m_data), &m_data));
  64. return *this;
  65. }
  66. tommath_int& operator=(boost::ulong_long_type i)
  67. {
  68. if (m_data.dp == 0)
  69. detail::check_tommath_result(mp_init(&m_data));
  70. boost::ulong_long_type mask = ((1uLL << std::numeric_limits<unsigned>::digits) - 1);
  71. unsigned shift = 0;
  72. ::mp_int t;
  73. detail::check_tommath_result(mp_init(&t));
  74. mp_zero(&m_data);
  75. while (i)
  76. {
  77. detail::check_tommath_result(mp_set_int(&t, static_cast<unsigned>(i & mask)));
  78. if (shift)
  79. detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
  80. detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
  81. shift += std::numeric_limits<unsigned>::digits;
  82. i >>= std::numeric_limits<unsigned>::digits;
  83. }
  84. mp_clear(&t);
  85. return *this;
  86. }
  87. tommath_int& operator=(boost::long_long_type i)
  88. {
  89. if (m_data.dp == 0)
  90. detail::check_tommath_result(mp_init(&m_data));
  91. bool neg = i < 0;
  92. *this = boost::multiprecision::detail::unsigned_abs(i);
  93. if (neg)
  94. detail::check_tommath_result(mp_neg(&m_data, &m_data));
  95. return *this;
  96. }
  97. //
  98. // Note that although mp_set_int takes an unsigned long as an argument
  99. // it only sets the first 32-bits to the result, and ignores the rest.
  100. // So use uint32_t as the largest type to pass to this function.
  101. //
  102. tommath_int& operator=(boost::uint32_t i)
  103. {
  104. if (m_data.dp == 0)
  105. detail::check_tommath_result(mp_init(&m_data));
  106. detail::check_tommath_result((mp_set_int(&m_data, i)));
  107. return *this;
  108. }
  109. tommath_int& operator=(boost::int32_t i)
  110. {
  111. if (m_data.dp == 0)
  112. detail::check_tommath_result(mp_init(&m_data));
  113. bool neg = i < 0;
  114. *this = boost::multiprecision::detail::unsigned_abs(i);
  115. if (neg)
  116. detail::check_tommath_result(mp_neg(&m_data, &m_data));
  117. return *this;
  118. }
  119. tommath_int& operator=(long double a)
  120. {
  121. using std::floor;
  122. using std::frexp;
  123. using std::ldexp;
  124. if (m_data.dp == 0)
  125. detail::check_tommath_result(mp_init(&m_data));
  126. if (a == 0)
  127. {
  128. detail::check_tommath_result(mp_set_int(&m_data, 0));
  129. return *this;
  130. }
  131. if (a == 1)
  132. {
  133. detail::check_tommath_result(mp_set_int(&m_data, 1));
  134. return *this;
  135. }
  136. BOOST_ASSERT(!(boost::math::isinf)(a));
  137. BOOST_ASSERT(!(boost::math::isnan)(a));
  138. int e;
  139. long double f, term;
  140. detail::check_tommath_result(mp_set_int(&m_data, 0u));
  141. ::mp_int t;
  142. detail::check_tommath_result(mp_init(&t));
  143. f = frexp(a, &e);
  144. static const int shift = std::numeric_limits<int>::digits - 1;
  145. while (f)
  146. {
  147. // extract int sized bits from f:
  148. f = ldexp(f, shift);
  149. term = floor(f);
  150. e -= shift;
  151. detail::check_tommath_result(mp_mul_2d(&m_data, shift, &m_data));
  152. if (term > 0)
  153. {
  154. detail::check_tommath_result(mp_set_int(&t, static_cast<int>(term)));
  155. detail::check_tommath_result(mp_add(&m_data, &t, &m_data));
  156. }
  157. else
  158. {
  159. detail::check_tommath_result(mp_set_int(&t, static_cast<int>(-term)));
  160. detail::check_tommath_result(mp_sub(&m_data, &t, &m_data));
  161. }
  162. f -= term;
  163. }
  164. if (e > 0)
  165. detail::check_tommath_result(mp_mul_2d(&m_data, e, &m_data));
  166. else if (e < 0)
  167. {
  168. tommath_int t2;
  169. detail::check_tommath_result(mp_div_2d(&m_data, -e, &m_data, &t2.data()));
  170. }
  171. mp_clear(&t);
  172. return *this;
  173. }
  174. tommath_int& operator=(const char* s)
  175. {
  176. //
  177. // We don't use libtommath's own routine because it doesn't error check the input :-(
  178. //
  179. if (m_data.dp == 0)
  180. detail::check_tommath_result(mp_init(&m_data));
  181. std::size_t n = s ? std::strlen(s) : 0;
  182. *this = static_cast<boost::uint32_t>(0u);
  183. unsigned radix = 10;
  184. bool isneg = false;
  185. if (n && (*s == '-'))
  186. {
  187. --n;
  188. ++s;
  189. isneg = true;
  190. }
  191. if (n && (*s == '0'))
  192. {
  193. if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
  194. {
  195. radix = 16;
  196. s += 2;
  197. n -= 2;
  198. }
  199. else
  200. {
  201. radix = 8;
  202. n -= 1;
  203. }
  204. }
  205. if (n)
  206. {
  207. if (radix == 8 || radix == 16)
  208. {
  209. unsigned shift = radix == 8 ? 3 : 4;
  210. unsigned block_count = DIGIT_BIT / shift;
  211. unsigned block_shift = shift * block_count;
  212. boost::ulong_long_type val, block;
  213. while (*s)
  214. {
  215. block = 0;
  216. for (unsigned i = 0; (i < block_count); ++i)
  217. {
  218. if (*s >= '0' && *s <= '9')
  219. val = *s - '0';
  220. else if (*s >= 'a' && *s <= 'f')
  221. val = 10 + *s - 'a';
  222. else if (*s >= 'A' && *s <= 'F')
  223. val = 10 + *s - 'A';
  224. else
  225. val = 400;
  226. if (val > radix)
  227. {
  228. BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
  229. }
  230. block <<= shift;
  231. block |= val;
  232. if (!*++s)
  233. {
  234. // final shift is different:
  235. block_shift = (i + 1) * shift;
  236. break;
  237. }
  238. }
  239. detail::check_tommath_result(mp_mul_2d(&data(), block_shift, &data()));
  240. if (data().used)
  241. data().dp[0] |= block;
  242. else
  243. *this = block;
  244. }
  245. }
  246. else
  247. {
  248. // Base 10, we extract blocks of size 10^9 at a time, that way
  249. // the number of multiplications is kept to a minimum:
  250. boost::uint32_t block_mult = 1000000000;
  251. while (*s)
  252. {
  253. boost::uint32_t block = 0;
  254. for (unsigned i = 0; i < 9; ++i)
  255. {
  256. boost::uint32_t val;
  257. if (*s >= '0' && *s <= '9')
  258. val = *s - '0';
  259. else
  260. BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected character encountered in input."));
  261. block *= 10;
  262. block += val;
  263. if (!*++s)
  264. {
  265. static const boost::uint32_t block_multiplier[9] = {10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
  266. block_mult = block_multiplier[i];
  267. break;
  268. }
  269. }
  270. tommath_int t;
  271. t = block_mult;
  272. eval_multiply(*this, t);
  273. t = block;
  274. eval_add(*this, t);
  275. }
  276. }
  277. }
  278. if (isneg)
  279. this->negate();
  280. return *this;
  281. }
  282. std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f) const
  283. {
  284. BOOST_ASSERT(m_data.dp);
  285. int base = 10;
  286. if ((f & std::ios_base::oct) == std::ios_base::oct)
  287. base = 8;
  288. else if ((f & std::ios_base::hex) == std::ios_base::hex)
  289. base = 16;
  290. //
  291. // sanity check, bases 8 and 16 are only available for positive numbers:
  292. //
  293. if ((base != 10) && m_data.sign)
  294. BOOST_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
  295. int s;
  296. detail::check_tommath_result(mp_radix_size(const_cast< ::mp_int*>(&m_data), base, &s));
  297. boost::scoped_array<char> a(new char[s + 1]);
  298. detail::check_tommath_result(mp_toradix_n(const_cast< ::mp_int*>(&m_data), a.get(), base, s + 1));
  299. std::string result = a.get();
  300. if (f & std::ios_base::uppercase)
  301. for (size_t i = 0; i < result.length(); ++i)
  302. result[i] = std::toupper(result[i]);
  303. if ((base != 10) && (f & std::ios_base::showbase))
  304. {
  305. int pos = result[0] == '-' ? 1 : 0;
  306. const char* pp = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
  307. result.insert(static_cast<std::string::size_type>(pos), pp);
  308. }
  309. if ((f & std::ios_base::showpos) && (result[0] != '-'))
  310. result.insert(static_cast<std::string::size_type>(0), 1, '+');
  311. return result;
  312. }
  313. ~tommath_int()
  314. {
  315. if (m_data.dp)
  316. mp_clear(&m_data);
  317. }
  318. void negate()
  319. {
  320. BOOST_ASSERT(m_data.dp);
  321. mp_neg(&m_data, &m_data);
  322. }
  323. int compare(const tommath_int& o) const
  324. {
  325. BOOST_ASSERT(m_data.dp && o.m_data.dp);
  326. return mp_cmp(const_cast< ::mp_int*>(&m_data), const_cast< ::mp_int*>(&o.m_data));
  327. }
  328. template <class V>
  329. int compare(V v) const
  330. {
  331. tommath_int d;
  332. tommath_int t(*this);
  333. detail::check_tommath_result(mp_shrink(&t.data()));
  334. d = v;
  335. return t.compare(d);
  336. }
  337. ::mp_int& data()
  338. {
  339. BOOST_ASSERT(m_data.dp);
  340. return m_data;
  341. }
  342. const ::mp_int& data() const
  343. {
  344. BOOST_ASSERT(m_data.dp);
  345. return m_data;
  346. }
  347. void swap(tommath_int& o) BOOST_NOEXCEPT
  348. {
  349. mp_exch(&m_data, &o.data());
  350. }
  351. protected:
  352. ::mp_int m_data;
  353. };
  354. #define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
  355. if (SIGN(&x.data())) \
  356. BOOST_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
  357. int eval_get_sign(const tommath_int& val);
  358. inline void eval_add(tommath_int& t, const tommath_int& o)
  359. {
  360. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  361. }
  362. inline void eval_subtract(tommath_int& t, const tommath_int& o)
  363. {
  364. detail::check_tommath_result(mp_sub(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  365. }
  366. inline void eval_multiply(tommath_int& t, const tommath_int& o)
  367. {
  368. detail::check_tommath_result(mp_mul(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  369. }
  370. inline void eval_divide(tommath_int& t, const tommath_int& o)
  371. {
  372. using default_ops::eval_is_zero;
  373. tommath_int temp;
  374. if (eval_is_zero(o))
  375. BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  376. detail::check_tommath_result(mp_div(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data(), &temp.data()));
  377. }
  378. inline void eval_modulus(tommath_int& t, const tommath_int& o)
  379. {
  380. using default_ops::eval_is_zero;
  381. if (eval_is_zero(o))
  382. BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  383. bool neg = eval_get_sign(t) < 0;
  384. bool neg2 = eval_get_sign(o) < 0;
  385. detail::check_tommath_result(mp_mod(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  386. if ((neg != neg2) && (eval_get_sign(t) != 0))
  387. {
  388. t.negate();
  389. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  390. t.negate();
  391. }
  392. else if (neg && (t.compare(o) == 0))
  393. {
  394. mp_zero(&t.data());
  395. }
  396. }
  397. template <class UI>
  398. inline void eval_left_shift(tommath_int& t, UI i)
  399. {
  400. detail::check_tommath_result(mp_mul_2d(&t.data(), static_cast<unsigned>(i), &t.data()));
  401. }
  402. template <class UI>
  403. inline void eval_right_shift(tommath_int& t, UI i)
  404. {
  405. using default_ops::eval_decrement;
  406. using default_ops::eval_increment;
  407. bool neg = eval_get_sign(t) < 0;
  408. tommath_int d;
  409. if (neg)
  410. eval_increment(t);
  411. detail::check_tommath_result(mp_div_2d(&t.data(), static_cast<unsigned>(i), &t.data(), &d.data()));
  412. if (neg)
  413. eval_decrement(t);
  414. }
  415. template <class UI>
  416. inline void eval_left_shift(tommath_int& t, const tommath_int& v, UI i)
  417. {
  418. detail::check_tommath_result(mp_mul_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned>(i), &t.data()));
  419. }
  420. /*
  421. template <class UI>
  422. inline void eval_right_shift(tommath_int& t, const tommath_int& v, UI i)
  423. {
  424. tommath_int d;
  425. detail::check_tommath_result(mp_div_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned long>(i), &t.data(), &d.data()));
  426. }
  427. */
  428. inline void eval_bitwise_and(tommath_int& result, const tommath_int& v)
  429. {
  430. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  431. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  432. detail::check_tommath_result(mp_and(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  433. }
  434. inline void eval_bitwise_or(tommath_int& result, const tommath_int& v)
  435. {
  436. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  437. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  438. detail::check_tommath_result(mp_or(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  439. }
  440. inline void eval_bitwise_xor(tommath_int& result, const tommath_int& v)
  441. {
  442. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  443. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  444. detail::check_tommath_result(mp_xor(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  445. }
  446. inline void eval_add(tommath_int& t, const tommath_int& p, const tommath_int& o)
  447. {
  448. detail::check_tommath_result(mp_add(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  449. }
  450. inline void eval_subtract(tommath_int& t, const tommath_int& p, const tommath_int& o)
  451. {
  452. detail::check_tommath_result(mp_sub(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  453. }
  454. inline void eval_multiply(tommath_int& t, const tommath_int& p, const tommath_int& o)
  455. {
  456. detail::check_tommath_result(mp_mul(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  457. }
  458. inline void eval_divide(tommath_int& t, const tommath_int& p, const tommath_int& o)
  459. {
  460. using default_ops::eval_is_zero;
  461. tommath_int d;
  462. if (eval_is_zero(o))
  463. BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  464. detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data(), &d.data()));
  465. }
  466. inline void eval_modulus(tommath_int& t, const tommath_int& p, const tommath_int& o)
  467. {
  468. using default_ops::eval_is_zero;
  469. if (eval_is_zero(o))
  470. BOOST_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  471. bool neg = eval_get_sign(p) < 0;
  472. bool neg2 = eval_get_sign(o) < 0;
  473. detail::check_tommath_result(mp_mod(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  474. if ((neg != neg2) && (eval_get_sign(t) != 0))
  475. {
  476. t.negate();
  477. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  478. t.negate();
  479. }
  480. else if (neg && (t.compare(o) == 0))
  481. {
  482. mp_zero(&t.data());
  483. }
  484. }
  485. inline void eval_bitwise_and(tommath_int& result, const tommath_int& u, const tommath_int& v)
  486. {
  487. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  488. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  489. detail::check_tommath_result(mp_and(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  490. }
  491. inline void eval_bitwise_or(tommath_int& result, const tommath_int& u, const tommath_int& v)
  492. {
  493. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  494. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  495. detail::check_tommath_result(mp_or(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  496. }
  497. inline void eval_bitwise_xor(tommath_int& result, const tommath_int& u, const tommath_int& v)
  498. {
  499. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  500. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  501. detail::check_tommath_result(mp_xor(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  502. }
  503. /*
  504. inline void eval_complement(tommath_int& result, const tommath_int& u)
  505. {
  506. //
  507. // Although this code works, it doesn't really do what the user might expect....
  508. // and it's hard to see how it ever could. Disabled for now:
  509. //
  510. result = u;
  511. for(int i = 0; i < result.data().used; ++i)
  512. {
  513. result.data().dp[i] = MP_MASK & ~(result.data().dp[i]);
  514. }
  515. //
  516. // We now need to pad out the left of the value with 1's to round up to a whole number of
  517. // CHAR_BIT * sizeof(mp_digit) units. Otherwise we'll end up with a very strange number of
  518. // bits set!
  519. //
  520. unsigned shift = result.data().used * DIGIT_BIT; // How many bits we're actually using
  521. // How many bits we actually need, reduced by one to account for a mythical sign bit:
  522. int padding = result.data().used * std::numeric_limits<mp_digit>::digits - shift - 1;
  523. while(padding >= std::numeric_limits<mp_digit>::digits)
  524. padding -= std::numeric_limits<mp_digit>::digits;
  525. // Create a mask providing the extra bits we need and add to result:
  526. tommath_int mask;
  527. mask = static_cast<boost::long_long_type>((1u << padding) - 1);
  528. eval_left_shift(mask, shift);
  529. add(result, mask);
  530. }
  531. */
  532. inline bool eval_is_zero(const tommath_int& val)
  533. {
  534. return mp_iszero(&val.data());
  535. }
  536. inline int eval_get_sign(const tommath_int& val)
  537. {
  538. return mp_iszero(&val.data()) ? 0 : SIGN(&val.data()) ? -1 : 1;
  539. }
  540. /*
  541. template <class A>
  542. inline void eval_convert_to(A* result, const tommath_int& val)
  543. {
  544. *result = boost::lexical_cast<A>(val.str(0, std::ios_base::fmtflags(0)));
  545. }
  546. inline void eval_convert_to(char* result, const tommath_int& val)
  547. {
  548. *result = static_cast<char>(boost::lexical_cast<int>(val.str(0, std::ios_base::fmtflags(0))));
  549. }
  550. inline void eval_convert_to(unsigned char* result, const tommath_int& val)
  551. {
  552. *result = static_cast<unsigned char>(boost::lexical_cast<unsigned>(val.str(0, std::ios_base::fmtflags(0))));
  553. }
  554. inline void eval_convert_to(signed char* result, const tommath_int& val)
  555. {
  556. *result = static_cast<signed char>(boost::lexical_cast<int>(val.str(0, std::ios_base::fmtflags(0))));
  557. }
  558. */
  559. inline void eval_abs(tommath_int& result, const tommath_int& val)
  560. {
  561. detail::check_tommath_result(mp_abs(const_cast< ::mp_int*>(&val.data()), &result.data()));
  562. }
  563. inline void eval_gcd(tommath_int& result, const tommath_int& a, const tommath_int& b)
  564. {
  565. detail::check_tommath_result(mp_gcd(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
  566. }
  567. inline void eval_lcm(tommath_int& result, const tommath_int& a, const tommath_int& b)
  568. {
  569. detail::check_tommath_result(mp_lcm(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
  570. }
  571. inline void eval_powm(tommath_int& result, const tommath_int& base, const tommath_int& p, const tommath_int& m)
  572. {
  573. if (eval_get_sign(p) < 0)
  574. {
  575. BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
  576. }
  577. detail::check_tommath_result(mp_exptmod(const_cast< ::mp_int*>(&base.data()), const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&m.data()), &result.data()));
  578. }
  579. inline void eval_qr(const tommath_int& x, const tommath_int& y,
  580. tommath_int& q, tommath_int& r)
  581. {
  582. detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&x.data()), const_cast< ::mp_int*>(&y.data()), &q.data(), &r.data()));
  583. }
  584. inline unsigned eval_lsb(const tommath_int& val)
  585. {
  586. int c = eval_get_sign(val);
  587. if (c == 0)
  588. {
  589. BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
  590. }
  591. if (c < 0)
  592. {
  593. BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
  594. }
  595. return mp_cnt_lsb(const_cast< ::mp_int*>(&val.data()));
  596. }
  597. inline unsigned eval_msb(const tommath_int& val)
  598. {
  599. int c = eval_get_sign(val);
  600. if (c == 0)
  601. {
  602. BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
  603. }
  604. if (c < 0)
  605. {
  606. BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
  607. }
  608. return mp_count_bits(const_cast< ::mp_int*>(&val.data())) - 1;
  609. }
  610. template <class Integer>
  611. inline typename enable_if<is_unsigned<Integer>, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
  612. {
  613. static const mp_digit m = (static_cast<mp_digit>(1) << DIGIT_BIT) - 1;
  614. if (val <= m)
  615. {
  616. mp_digit d;
  617. detail::check_tommath_result(mp_mod_d(const_cast< ::mp_int*>(&x.data()), static_cast<mp_digit>(val), &d));
  618. return d;
  619. }
  620. else
  621. {
  622. return default_ops::eval_integer_modulus(x, val);
  623. }
  624. }
  625. template <class Integer>
  626. inline typename enable_if<is_signed<Integer>, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
  627. {
  628. return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
  629. }
  630. inline std::size_t hash_value(const tommath_int& val)
  631. {
  632. std::size_t result = 0;
  633. std::size_t len = val.data().used;
  634. for (std::size_t i = 0; i < len; ++i)
  635. boost::hash_combine(result, val.data().dp[i]);
  636. boost::hash_combine(result, val.data().sign);
  637. return result;
  638. }
  639. } // namespace backends
  640. using boost::multiprecision::backends::tommath_int;
  641. template <>
  642. struct number_category<tommath_int> : public mpl::int_<number_kind_integer>
  643. {};
  644. typedef number<tommath_int> tom_int;
  645. typedef rational_adaptor<tommath_int> tommath_rational;
  646. typedef number<tommath_rational> tom_rational;
  647. }} // namespace boost::multiprecision
  648. namespace std {
  649. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  650. class numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >
  651. {
  652. typedef boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> number_type;
  653. public:
  654. BOOST_STATIC_CONSTEXPR bool is_specialized = true;
  655. //
  656. // Largest and smallest numbers are bounded only by available memory, set
  657. // to zero:
  658. //
  659. static number_type(min)()
  660. {
  661. return number_type();
  662. }
  663. static number_type(max)()
  664. {
  665. return number_type();
  666. }
  667. static number_type lowest() { return (min)(); }
  668. BOOST_STATIC_CONSTEXPR int digits = INT_MAX;
  669. BOOST_STATIC_CONSTEXPR int digits10 = (INT_MAX / 1000) * 301L;
  670. BOOST_STATIC_CONSTEXPR int max_digits10 = digits10 + 3;
  671. BOOST_STATIC_CONSTEXPR bool is_signed = true;
  672. BOOST_STATIC_CONSTEXPR bool is_integer = true;
  673. BOOST_STATIC_CONSTEXPR bool is_exact = true;
  674. BOOST_STATIC_CONSTEXPR int radix = 2;
  675. static number_type epsilon() { return number_type(); }
  676. static number_type round_error() { return number_type(); }
  677. BOOST_STATIC_CONSTEXPR int min_exponent = 0;
  678. BOOST_STATIC_CONSTEXPR int min_exponent10 = 0;
  679. BOOST_STATIC_CONSTEXPR int max_exponent = 0;
  680. BOOST_STATIC_CONSTEXPR int max_exponent10 = 0;
  681. BOOST_STATIC_CONSTEXPR bool has_infinity = false;
  682. BOOST_STATIC_CONSTEXPR bool has_quiet_NaN = false;
  683. BOOST_STATIC_CONSTEXPR bool has_signaling_NaN = false;
  684. BOOST_STATIC_CONSTEXPR float_denorm_style has_denorm = denorm_absent;
  685. BOOST_STATIC_CONSTEXPR bool has_denorm_loss = false;
  686. static number_type infinity() { return number_type(); }
  687. static number_type quiet_NaN() { return number_type(); }
  688. static number_type signaling_NaN() { return number_type(); }
  689. static number_type denorm_min() { return number_type(); }
  690. BOOST_STATIC_CONSTEXPR bool is_iec559 = false;
  691. BOOST_STATIC_CONSTEXPR bool is_bounded = false;
  692. BOOST_STATIC_CONSTEXPR bool is_modulo = false;
  693. BOOST_STATIC_CONSTEXPR bool traps = false;
  694. BOOST_STATIC_CONSTEXPR bool tinyness_before = false;
  695. BOOST_STATIC_CONSTEXPR float_round_style round_style = round_toward_zero;
  696. };
  697. #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
  698. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  699. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits;
  700. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  701. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits10;
  702. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  703. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_digits10;
  704. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  705. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_signed;
  706. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  707. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_integer;
  708. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  709. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_exact;
  710. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  711. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::radix;
  712. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  713. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent;
  714. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  715. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent10;
  716. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  717. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent;
  718. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  719. BOOST_CONSTEXPR_OR_CONST int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent10;
  720. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  721. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_infinity;
  722. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  723. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_quiet_NaN;
  724. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  725. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_signaling_NaN;
  726. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  727. BOOST_CONSTEXPR_OR_CONST float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm;
  728. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  729. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm_loss;
  730. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  731. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_iec559;
  732. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  733. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_bounded;
  734. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  735. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_modulo;
  736. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  737. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::traps;
  738. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  739. BOOST_CONSTEXPR_OR_CONST bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::tinyness_before;
  740. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  741. BOOST_CONSTEXPR_OR_CONST float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::round_style;
  742. #endif
  743. } // namespace std
  744. #endif