tommath.hpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2011 John Maddock.
  3. // Copyright 2021 Matt Borland. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_MP_TOMMATH_HPP
  7. #define BOOST_MP_TOMMATH_HPP
  8. #include <cctype>
  9. #include <climits>
  10. #include <cmath>
  11. #include <cstdint>
  12. #include <cstddef>
  13. #include <cstdlib>
  14. #include <limits>
  15. #include <memory>
  16. #include <string>
  17. #include <tommath.h>
  18. #include <boost/multiprecision/detail/standalone_config.hpp>
  19. #include <boost/multiprecision/detail/fpclassify.hpp>
  20. #include <boost/multiprecision/number.hpp>
  21. #include <boost/multiprecision/rational_adaptor.hpp>
  22. #include <boost/multiprecision/detail/integer_ops.hpp>
  23. #include <boost/multiprecision/detail/hash.hpp>
  24. #include <boost/multiprecision/detail/no_exceptions_support.hpp>
  25. #include <boost/multiprecision/detail/assert.hpp>
  26. namespace boost {
  27. namespace multiprecision {
  28. namespace backends {
  29. namespace detail {
  30. template <class ErrType>
  31. inline void check_tommath_result(ErrType v)
  32. {
  33. if (v != MP_OKAY)
  34. {
  35. BOOST_MP_THROW_EXCEPTION(std::runtime_error(mp_error_to_string(v)));
  36. }
  37. }
  38. } // namespace detail
  39. void eval_multiply(tommath_int& t, const tommath_int& o);
  40. void eval_add(tommath_int& t, const tommath_int& o);
  41. struct tommath_int
  42. {
  43. using signed_types = std::tuple<std::int32_t, long long> ;
  44. using unsigned_types = std::tuple<std::uint32_t, unsigned long long>;
  45. using float_types = std::tuple<long double> ;
  46. tommath_int()
  47. {
  48. detail::check_tommath_result(mp_init(&m_data));
  49. }
  50. tommath_int(const tommath_int& o)
  51. {
  52. detail::check_tommath_result(mp_init_copy(&m_data, const_cast< ::mp_int*>(&o.m_data)));
  53. }
  54. // rvalues:
  55. tommath_int(tommath_int&& o) noexcept
  56. {
  57. m_data = o.m_data;
  58. o.m_data.dp = 0;
  59. }
  60. tommath_int& operator=(tommath_int&& o)
  61. {
  62. mp_exch(&m_data, &o.m_data);
  63. return *this;
  64. }
  65. tommath_int& operator=(const tommath_int& o)
  66. {
  67. if (m_data.dp == nullptr)
  68. detail::check_tommath_result(mp_init(&m_data));
  69. if (o.m_data.dp)
  70. detail::check_tommath_result(mp_copy(const_cast< ::mp_int*>(&o.m_data), &m_data));
  71. return *this;
  72. }
  73. #ifndef mp_get_u64
  74. // Pick off 32 bit chunks for mp_set_int:
  75. tommath_int& operator=(unsigned long long i)
  76. {
  77. if (m_data.dp == nullptr)
  78. detail::check_tommath_result(mp_init(&m_data));
  79. unsigned long long mask = ((1uLL << 32) - 1);
  80. unsigned shift = 0;
  81. ::mp_int t;
  82. detail::check_tommath_result(mp_init(&t));
  83. mp_zero(&m_data);
  84. while (i)
  85. {
  86. detail::check_tommath_result(mp_set_int(&t, static_cast<unsigned>(i & mask)));
  87. if (shift)
  88. detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
  89. detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
  90. shift += 32;
  91. i >>= 32;
  92. }
  93. mp_clear(&t);
  94. return *this;
  95. }
  96. #elif !defined(ULLONG_MAX) || (ULLONG_MAX != 18446744073709551615uLL)
  97. // Pick off 64 bit chunks for mp_set_u64:
  98. tommath_int& operator=(unsigned long long i)
  99. {
  100. if (m_data.dp == nullptr)
  101. detail::check_tommath_result(mp_init(&m_data));
  102. if(sizeof(unsigned long long) * CHAR_BIT == 64)
  103. {
  104. mp_set_u64(&m_data, i);
  105. return *this;
  106. }
  107. unsigned long long mask = ((1uLL << 64) - 1);
  108. unsigned shift = 0;
  109. ::mp_int t;
  110. detail::check_tommath_result(mp_init(&t));
  111. mp_zero(&m_data);
  112. while (i)
  113. {
  114. detail::check_tommath_result(mp_set_u64(&t, static_cast<std::uint64_t>(i & mask)));
  115. if (shift)
  116. detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
  117. detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
  118. shift += 64;
  119. i >>= 64;
  120. }
  121. mp_clear(&t);
  122. return *this;
  123. }
  124. #else
  125. tommath_int& operator=(unsigned long long i)
  126. {
  127. if (m_data.dp == nullptr)
  128. detail::check_tommath_result(mp_init(&m_data));
  129. mp_set_u64(&m_data, i);
  130. return *this;
  131. }
  132. #endif
  133. tommath_int& operator=(long long i)
  134. {
  135. if (m_data.dp == nullptr)
  136. detail::check_tommath_result(mp_init(&m_data));
  137. bool neg = i < 0;
  138. *this = boost::multiprecision::detail::unsigned_abs(i);
  139. if (neg)
  140. detail::check_tommath_result(mp_neg(&m_data, &m_data));
  141. return *this;
  142. }
  143. #ifdef BOOST_HAS_INT128
  144. // Pick off 64 bit chunks for mp_set_u64:
  145. tommath_int& operator=(uint128_type i)
  146. {
  147. if (m_data.dp == nullptr)
  148. detail::check_tommath_result(mp_init(&m_data));
  149. int128_type mask = ((static_cast<uint128_type>(1u) << 64) - 1);
  150. unsigned shift = 0;
  151. ::mp_int t;
  152. detail::check_tommath_result(mp_init(&t));
  153. mp_zero(&m_data);
  154. while (i)
  155. {
  156. #ifndef mp_get_u32
  157. detail::check_tommath_result(mp_set_long_long(&t, static_cast<std::uint64_t>(i & mask)));
  158. #else
  159. mp_set_u64(&t, static_cast<std::uint64_t>(i & mask));
  160. #endif
  161. if (shift)
  162. detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
  163. detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
  164. shift += 64;
  165. i >>= 64;
  166. }
  167. mp_clear(&t);
  168. return *this;
  169. }
  170. tommath_int& operator=(int128_type i)
  171. {
  172. if (m_data.dp == nullptr)
  173. detail::check_tommath_result(mp_init(&m_data));
  174. bool neg = i < 0;
  175. *this = boost::multiprecision::detail::unsigned_abs(i);
  176. if (neg)
  177. detail::check_tommath_result(mp_neg(&m_data, &m_data));
  178. return *this;
  179. }
  180. #endif
  181. //
  182. // Note that although mp_set_int takes an unsigned long as an argument
  183. // it only sets the first 32-bits to the result, and ignores the rest.
  184. // So use uint32_t as the largest type to pass to this function.
  185. //
  186. tommath_int& operator=(std::uint32_t i)
  187. {
  188. if (m_data.dp == nullptr)
  189. detail::check_tommath_result(mp_init(&m_data));
  190. #ifndef mp_get_u32
  191. detail::check_tommath_result((mp_set_int(&m_data, i)));
  192. #else
  193. mp_set_u32(&m_data, i);
  194. #endif
  195. return *this;
  196. }
  197. tommath_int& operator=(std::int32_t i)
  198. {
  199. if (m_data.dp == nullptr)
  200. detail::check_tommath_result(mp_init(&m_data));
  201. bool neg = i < 0;
  202. *this = boost::multiprecision::detail::unsigned_abs(i);
  203. if (neg)
  204. detail::check_tommath_result(mp_neg(&m_data, &m_data));
  205. return *this;
  206. }
  207. template <class F>
  208. tommath_int& assign_float(F a)
  209. {
  210. BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
  211. if (m_data.dp == nullptr)
  212. detail::check_tommath_result(mp_init(&m_data));
  213. if (a == 0)
  214. {
  215. #ifndef mp_get_u32
  216. detail::check_tommath_result(mp_set_int(&m_data, 0));
  217. #else
  218. mp_set_i32(&m_data, 0);
  219. #endif
  220. return *this;
  221. }
  222. if (a == 1)
  223. {
  224. #ifndef mp_get_u32
  225. detail::check_tommath_result(mp_set_int(&m_data, 1));
  226. #else
  227. mp_set_i32(&m_data, 1);
  228. #endif
  229. return *this;
  230. }
  231. BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
  232. BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
  233. int e;
  234. F f, term;
  235. #ifndef mp_get_u32
  236. detail::check_tommath_result(mp_set_int(&m_data, 0u));
  237. #else
  238. mp_set_i32(&m_data, 0);
  239. #endif
  240. ::mp_int t;
  241. detail::check_tommath_result(mp_init(&t));
  242. f = frexp(a, &e);
  243. #ifdef MP_DIGIT_BIT
  244. constexpr const int shift = std::numeric_limits<int>::digits - 1;
  245. using part_type = int ;
  246. #else
  247. constexpr const int shift = std::numeric_limits<std::int64_t>::digits - 1;
  248. using part_type = std::int64_t;
  249. #endif
  250. while (f)
  251. {
  252. // extract int sized bits from f:
  253. f = ldexp(f, shift);
  254. term = floor(f);
  255. e -= shift;
  256. detail::check_tommath_result(mp_mul_2d(&m_data, shift, &m_data));
  257. if (term > 0)
  258. {
  259. #ifndef mp_get_u64
  260. detail::check_tommath_result(mp_set_int(&t, static_cast<part_type>(term)));
  261. #else
  262. mp_set_i64(&t, static_cast<part_type>(term));
  263. #endif
  264. detail::check_tommath_result(mp_add(&m_data, &t, &m_data));
  265. }
  266. else
  267. {
  268. #ifndef mp_get_u64
  269. detail::check_tommath_result(mp_set_int(&t, static_cast<part_type>(-term)));
  270. #else
  271. mp_set_i64(&t, static_cast<part_type>(-term));
  272. #endif
  273. detail::check_tommath_result(mp_sub(&m_data, &t, &m_data));
  274. }
  275. f -= term;
  276. }
  277. if (e > 0)
  278. detail::check_tommath_result(mp_mul_2d(&m_data, e, &m_data));
  279. else if (e < 0)
  280. {
  281. tommath_int t2;
  282. detail::check_tommath_result(mp_div_2d(&m_data, -e, &m_data, &t2.data()));
  283. }
  284. mp_clear(&t);
  285. return *this;
  286. }
  287. tommath_int& operator=(long double a)
  288. {
  289. return assign_float(a);
  290. }
  291. #ifdef BOOST_HAS_FLOAT128
  292. tommath_int& operator= (float128_type a)
  293. {
  294. return assign_float(a);
  295. }
  296. #endif
  297. tommath_int& operator=(const char* s)
  298. {
  299. //
  300. // We don't use libtommath's own routine because it doesn't error check the input :-(
  301. //
  302. if (m_data.dp == nullptr)
  303. detail::check_tommath_result(mp_init(&m_data));
  304. std::size_t n = s ? std::strlen(s) : 0;
  305. *this = static_cast<std::uint32_t>(0u);
  306. unsigned radix = 10;
  307. bool isneg = false;
  308. if (n && (*s == '-'))
  309. {
  310. --n;
  311. ++s;
  312. isneg = true;
  313. }
  314. if (n && (*s == '0'))
  315. {
  316. if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
  317. {
  318. radix = 16;
  319. s += 2;
  320. n -= 2;
  321. }
  322. else
  323. {
  324. radix = 8;
  325. n -= 1;
  326. }
  327. }
  328. if (n)
  329. {
  330. if (radix == 8 || radix == 16)
  331. {
  332. unsigned shift = radix == 8 ? 3 : 4;
  333. #ifndef MP_DIGIT_BIT
  334. unsigned block_count = DIGIT_BIT / shift;
  335. #else
  336. unsigned block_count = MP_DIGIT_BIT / shift;
  337. #endif
  338. unsigned block_shift = shift * block_count;
  339. unsigned long long val, block;
  340. while (*s)
  341. {
  342. block = 0;
  343. for (unsigned i = 0; (i < block_count); ++i)
  344. {
  345. if (*s >= '0' && *s <= '9')
  346. val = *s - '0';
  347. else if (*s >= 'a' && *s <= 'f')
  348. val = 10 + *s - 'a';
  349. else if (*s >= 'A' && *s <= 'F')
  350. val = 10 + *s - 'A';
  351. else
  352. val = 400;
  353. if (val > radix)
  354. {
  355. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
  356. }
  357. block <<= shift;
  358. block |= val;
  359. if (!*++s)
  360. {
  361. // final shift is different:
  362. block_shift = (i + 1) * shift;
  363. break;
  364. }
  365. }
  366. detail::check_tommath_result(mp_mul_2d(&data(), block_shift, &data()));
  367. if (data().used)
  368. data().dp[0] |= block;
  369. else
  370. *this = block;
  371. }
  372. }
  373. else
  374. {
  375. // Base 10, we extract blocks of size 10^9 at a time, that way
  376. // the number of multiplications is kept to a minimum:
  377. std::uint32_t block_mult = 1000000000;
  378. while (*s)
  379. {
  380. std::uint32_t block = 0;
  381. for (unsigned i = 0; i < 9; ++i)
  382. {
  383. std::uint32_t val;
  384. if (*s >= '0' && *s <= '9')
  385. val = *s - '0';
  386. else
  387. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Unexpected character encountered in input."));
  388. block *= 10;
  389. block += val;
  390. if (!*++s)
  391. {
  392. constexpr const std::uint32_t block_multiplier[9] = {10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
  393. block_mult = block_multiplier[i];
  394. break;
  395. }
  396. }
  397. tommath_int t;
  398. t = block_mult;
  399. eval_multiply(*this, t);
  400. t = block;
  401. eval_add(*this, t);
  402. }
  403. }
  404. }
  405. if (isneg)
  406. this->negate();
  407. return *this;
  408. }
  409. std::string str(std::streamsize /*digits*/, std::ios_base::fmtflags f) const
  410. {
  411. BOOST_MP_ASSERT(m_data.dp);
  412. int base = 10;
  413. if ((f & std::ios_base::oct) == std::ios_base::oct)
  414. base = 8;
  415. else if ((f & std::ios_base::hex) == std::ios_base::hex)
  416. base = 16;
  417. //
  418. // sanity check, bases 8 and 16 are only available for positive numbers:
  419. //
  420. if ((base != 10) && m_data.sign)
  421. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
  422. int s;
  423. detail::check_tommath_result(mp_radix_size(const_cast< ::mp_int*>(&m_data), base, &s));
  424. std::unique_ptr<char[]> a(new char[s + 1]);
  425. #ifndef mp_to_binary
  426. detail::check_tommath_result(mp_toradix_n(const_cast< ::mp_int*>(&m_data), a.get(), base, s + 1));
  427. #else
  428. std::size_t written;
  429. detail::check_tommath_result(mp_to_radix(&m_data, a.get(), s + 1, &written, base));
  430. #endif
  431. std::string result = a.get();
  432. if (f & std::ios_base::uppercase)
  433. for (size_t i = 0; i < result.length(); ++i)
  434. result[i] = std::toupper(result[i]);
  435. if ((base != 10) && (f & std::ios_base::showbase))
  436. {
  437. int pos = result[0] == '-' ? 1 : 0;
  438. const char* pp = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
  439. result.insert(static_cast<std::string::size_type>(pos), pp);
  440. }
  441. if ((f & std::ios_base::showpos) && (result[0] != '-'))
  442. result.insert(static_cast<std::string::size_type>(0), 1, '+');
  443. if (((f & std::ios_base::uppercase) == 0) && (base == 16))
  444. {
  445. for (std::size_t i = 0; i < result.size(); ++i)
  446. result[i] = std::tolower(result[i]);
  447. }
  448. return result;
  449. }
  450. ~tommath_int()
  451. {
  452. if (m_data.dp)
  453. mp_clear(&m_data);
  454. }
  455. void negate()
  456. {
  457. BOOST_MP_ASSERT(m_data.dp);
  458. detail::check_tommath_result(mp_neg(&m_data, &m_data));
  459. }
  460. int compare(const tommath_int& o) const
  461. {
  462. BOOST_MP_ASSERT(m_data.dp && o.m_data.dp);
  463. return mp_cmp(const_cast< ::mp_int*>(&m_data), const_cast< ::mp_int*>(&o.m_data));
  464. }
  465. template <class V>
  466. int compare(V v) const
  467. {
  468. tommath_int d;
  469. tommath_int t(*this);
  470. detail::check_tommath_result(mp_shrink(&t.data()));
  471. d = v;
  472. return t.compare(d);
  473. }
  474. ::mp_int& data()
  475. {
  476. BOOST_MP_ASSERT(m_data.dp);
  477. return m_data;
  478. }
  479. const ::mp_int& data() const
  480. {
  481. BOOST_MP_ASSERT(m_data.dp);
  482. return m_data;
  483. }
  484. void swap(tommath_int& o) noexcept
  485. {
  486. mp_exch(&m_data, &o.data());
  487. }
  488. protected:
  489. ::mp_int m_data;
  490. };
  491. #ifndef mp_isneg
  492. #define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
  493. if (SIGN(&x.data())) \
  494. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
  495. #else
  496. #define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
  497. if (mp_isneg(&x.data())) \
  498. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
  499. #endif
  500. int eval_get_sign(const tommath_int& val);
  501. inline void eval_add(tommath_int& t, const tommath_int& o)
  502. {
  503. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  504. }
  505. inline void eval_subtract(tommath_int& t, const tommath_int& o)
  506. {
  507. detail::check_tommath_result(mp_sub(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  508. }
  509. inline void eval_multiply(tommath_int& t, const tommath_int& o)
  510. {
  511. detail::check_tommath_result(mp_mul(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  512. }
  513. inline void eval_divide(tommath_int& t, const tommath_int& o)
  514. {
  515. using default_ops::eval_is_zero;
  516. tommath_int temp;
  517. if (eval_is_zero(o))
  518. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  519. detail::check_tommath_result(mp_div(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data(), &temp.data()));
  520. }
  521. inline void eval_modulus(tommath_int& t, const tommath_int& o)
  522. {
  523. using default_ops::eval_is_zero;
  524. if (eval_is_zero(o))
  525. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  526. bool neg = eval_get_sign(t) < 0;
  527. bool neg2 = eval_get_sign(o) < 0;
  528. detail::check_tommath_result(mp_mod(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  529. if ((neg != neg2) && (eval_get_sign(t) != 0))
  530. {
  531. t.negate();
  532. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  533. t.negate();
  534. }
  535. else if (neg && (t.compare(o) == 0))
  536. {
  537. mp_zero(&t.data());
  538. }
  539. }
  540. template <class UI>
  541. inline void eval_left_shift(tommath_int& t, UI i)
  542. {
  543. detail::check_tommath_result(mp_mul_2d(&t.data(), static_cast<unsigned>(i), &t.data()));
  544. }
  545. template <class UI>
  546. inline void eval_right_shift(tommath_int& t, UI i)
  547. {
  548. using default_ops::eval_decrement;
  549. using default_ops::eval_increment;
  550. bool neg = eval_get_sign(t) < 0;
  551. tommath_int d;
  552. if (neg)
  553. eval_increment(t);
  554. detail::check_tommath_result(mp_div_2d(&t.data(), static_cast<unsigned>(i), &t.data(), &d.data()));
  555. if (neg)
  556. eval_decrement(t);
  557. }
  558. template <class UI>
  559. inline void eval_left_shift(tommath_int& t, const tommath_int& v, UI i)
  560. {
  561. detail::check_tommath_result(mp_mul_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned>(i), &t.data()));
  562. }
  563. /*
  564. template <class UI>
  565. inline void eval_right_shift(tommath_int& t, const tommath_int& v, UI i)
  566. {
  567. tommath_int d;
  568. detail::check_tommath_result(mp_div_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned long>(i), &t.data(), &d.data()));
  569. }
  570. */
  571. inline void eval_bitwise_and(tommath_int& result, const tommath_int& v)
  572. {
  573. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  574. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  575. detail::check_tommath_result(mp_and(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  576. }
  577. inline void eval_bitwise_or(tommath_int& result, const tommath_int& v)
  578. {
  579. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  580. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  581. detail::check_tommath_result(mp_or(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  582. }
  583. inline void eval_bitwise_xor(tommath_int& result, const tommath_int& v)
  584. {
  585. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  586. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  587. detail::check_tommath_result(mp_xor(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  588. }
  589. inline void eval_add(tommath_int& t, const tommath_int& p, const tommath_int& o)
  590. {
  591. detail::check_tommath_result(mp_add(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  592. }
  593. inline void eval_subtract(tommath_int& t, const tommath_int& p, const tommath_int& o)
  594. {
  595. detail::check_tommath_result(mp_sub(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  596. }
  597. inline void eval_multiply(tommath_int& t, const tommath_int& p, const tommath_int& o)
  598. {
  599. detail::check_tommath_result(mp_mul(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  600. }
  601. inline void eval_divide(tommath_int& t, const tommath_int& p, const tommath_int& o)
  602. {
  603. using default_ops::eval_is_zero;
  604. tommath_int d;
  605. if (eval_is_zero(o))
  606. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  607. detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data(), &d.data()));
  608. }
  609. inline void eval_modulus(tommath_int& t, const tommath_int& p, const tommath_int& o)
  610. {
  611. using default_ops::eval_is_zero;
  612. if (eval_is_zero(o))
  613. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  614. bool neg = eval_get_sign(p) < 0;
  615. bool neg2 = eval_get_sign(o) < 0;
  616. detail::check_tommath_result(mp_mod(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  617. if ((neg != neg2) && (eval_get_sign(t) != 0))
  618. {
  619. t.negate();
  620. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  621. t.negate();
  622. }
  623. else if (neg && (t.compare(o) == 0))
  624. {
  625. mp_zero(&t.data());
  626. }
  627. }
  628. inline void eval_bitwise_and(tommath_int& result, const tommath_int& u, const tommath_int& v)
  629. {
  630. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  631. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  632. detail::check_tommath_result(mp_and(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  633. }
  634. inline void eval_bitwise_or(tommath_int& result, const tommath_int& u, const tommath_int& v)
  635. {
  636. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  637. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  638. detail::check_tommath_result(mp_or(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  639. }
  640. inline void eval_bitwise_xor(tommath_int& result, const tommath_int& u, const tommath_int& v)
  641. {
  642. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  643. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  644. detail::check_tommath_result(mp_xor(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  645. }
  646. /*
  647. inline void eval_complement(tommath_int& result, const tommath_int& u)
  648. {
  649. //
  650. // Although this code works, it doesn't really do what the user might expect....
  651. // and it's hard to see how it ever could. Disabled for now:
  652. //
  653. result = u;
  654. for(int i = 0; i < result.data().used; ++i)
  655. {
  656. result.data().dp[i] = MP_MASK & ~(result.data().dp[i]);
  657. }
  658. //
  659. // We now need to pad out the left of the value with 1's to round up to a whole number of
  660. // CHAR_BIT * sizeof(mp_digit) units. Otherwise we'll end up with a very strange number of
  661. // bits set!
  662. //
  663. unsigned shift = result.data().used * DIGIT_BIT; // How many bits we're actually using
  664. // How many bits we actually need, reduced by one to account for a mythical sign bit:
  665. int padding = result.data().used * std::numeric_limits<mp_digit>::digits - shift - 1;
  666. while(padding >= std::numeric_limits<mp_digit>::digits)
  667. padding -= std::numeric_limits<mp_digit>::digits;
  668. // Create a mask providing the extra bits we need and add to result:
  669. tommath_int mask;
  670. mask = static_cast<long long>((1u << padding) - 1);
  671. eval_left_shift(mask, shift);
  672. add(result, mask);
  673. }
  674. */
  675. inline bool eval_is_zero(const tommath_int& val)
  676. {
  677. return mp_iszero(&val.data());
  678. }
  679. inline int eval_get_sign(const tommath_int& val)
  680. {
  681. #ifndef mp_isneg
  682. return mp_iszero(&val.data()) ? 0 : SIGN(&val.data()) ? -1 : 1;
  683. #else
  684. return mp_iszero(&val.data()) ? 0 : mp_isneg(&val.data()) ? -1 : 1;
  685. #endif
  686. }
  687. inline void eval_convert_to(unsigned long long* result, const tommath_int& val)
  688. {
  689. if (mp_isneg(&val.data()))
  690. {
  691. BOOST_MP_THROW_EXCEPTION(std::range_error("Converting negative arbitrary precision value to unsigned."));
  692. }
  693. #ifdef MP_DEPRECATED
  694. *result = mp_get_ull(&val.data());
  695. #else
  696. *result = mp_get_long_long(const_cast<mp_int*>(&val.data()));
  697. #endif
  698. }
  699. inline void eval_convert_to(long long* result, const tommath_int& val)
  700. {
  701. if (!mp_iszero(&val.data()) && (mp_count_bits(const_cast<::mp_int*>(&val.data())) > std::numeric_limits<long long>::digits))
  702. {
  703. *result = mp_isneg(&val.data()) ? (std::numeric_limits<long long>::min)() : (std::numeric_limits<long long>::max)();
  704. return;
  705. }
  706. #ifdef MP_DEPRECATED
  707. unsigned long long r = mp_get_mag_ull(&val.data());
  708. #else
  709. unsigned long long r = mp_get_long_long(const_cast<mp_int*>(&val.data()));
  710. #endif
  711. if (mp_isneg(&val.data()))
  712. *result = -static_cast<long long>(r);
  713. else
  714. *result = r;
  715. }
  716. #ifdef BOOST_HAS_INT128
  717. inline void eval_convert_to(uint128_type* result, const tommath_int& val)
  718. {
  719. #ifdef MP_DEPRECATED
  720. if (mp_ubin_size(&val.data()) > sizeof(uint128_type))
  721. {
  722. *result = ~static_cast<uint128_type>(0);
  723. return;
  724. }
  725. unsigned char buf[sizeof(uint128_type)];
  726. std::size_t len;
  727. detail::check_tommath_result(mp_to_ubin(&val.data(), buf, sizeof(buf), &len));
  728. *result = 0;
  729. for (std::size_t i = 0; i < len; ++i)
  730. {
  731. *result <<= CHAR_BIT;
  732. *result |= buf[i];
  733. }
  734. #else
  735. std::size_t len = mp_unsigned_bin_size(const_cast<mp_int*>(&val.data()));
  736. if (len > sizeof(uint128_type))
  737. {
  738. *result = ~static_cast<uint128_type>(0);
  739. return;
  740. }
  741. unsigned char buf[sizeof(uint128_type)];
  742. detail::check_tommath_result(mp_to_unsigned_bin(const_cast<mp_int*>(&val.data()), buf));
  743. *result = 0;
  744. for (std::size_t i = 0; i < len; ++i)
  745. {
  746. *result <<= CHAR_BIT;
  747. *result |= buf[i];
  748. }
  749. #endif
  750. }
  751. inline void eval_convert_to(int128_type* result, const tommath_int& val)
  752. {
  753. uint128_type r;
  754. eval_convert_to(&r, val);
  755. if (mp_isneg(&val.data()))
  756. *result = -static_cast<int128_type>(r);
  757. else
  758. *result = r;
  759. }
  760. #endif
  761. #if defined(BOOST_HAS_FLOAT128)
  762. inline void eval_convert_to(float128_type* result, const tommath_int& val) noexcept
  763. {
  764. *result = float128_procs::strtoflt128(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  765. }
  766. #endif
  767. inline void eval_convert_to(long double* result, const tommath_int& val) noexcept
  768. {
  769. *result = std::strtold(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  770. }
  771. inline void eval_convert_to(double* result, const tommath_int& val) noexcept
  772. {
  773. *result = std::strtod(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  774. }
  775. inline void eval_convert_to(float* result, const tommath_int& val) noexcept
  776. {
  777. *result = std::strtof(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  778. }
  779. inline void eval_abs(tommath_int& result, const tommath_int& val)
  780. {
  781. detail::check_tommath_result(mp_abs(const_cast< ::mp_int*>(&val.data()), &result.data()));
  782. }
  783. inline void eval_gcd(tommath_int& result, const tommath_int& a, const tommath_int& b)
  784. {
  785. detail::check_tommath_result(mp_gcd(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
  786. }
  787. inline void eval_lcm(tommath_int& result, const tommath_int& a, const tommath_int& b)
  788. {
  789. detail::check_tommath_result(mp_lcm(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
  790. }
  791. inline void eval_powm(tommath_int& result, const tommath_int& base, const tommath_int& p, const tommath_int& m)
  792. {
  793. if (eval_get_sign(p) < 0)
  794. {
  795. BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
  796. }
  797. 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()));
  798. }
  799. inline void eval_qr(const tommath_int& x, const tommath_int& y,
  800. tommath_int& q, tommath_int& r)
  801. {
  802. detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&x.data()), const_cast< ::mp_int*>(&y.data()), &q.data(), &r.data()));
  803. }
  804. inline std::size_t eval_lsb(const tommath_int& val)
  805. {
  806. int c = eval_get_sign(val);
  807. if (c == 0)
  808. {
  809. BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
  810. }
  811. if (c < 0)
  812. {
  813. BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
  814. }
  815. return mp_cnt_lsb(const_cast< ::mp_int*>(&val.data()));
  816. }
  817. inline std::size_t eval_msb(const tommath_int& val)
  818. {
  819. int c = eval_get_sign(val);
  820. if (c == 0)
  821. {
  822. BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
  823. }
  824. if (c < 0)
  825. {
  826. BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
  827. }
  828. return mp_count_bits(const_cast< ::mp_int*>(&val.data())) - 1;
  829. }
  830. template <class Integer>
  831. inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
  832. {
  833. #ifndef MP_DIGIT_BIT
  834. constexpr const mp_digit m = (static_cast<mp_digit>(1) << DIGIT_BIT) - 1;
  835. #else
  836. constexpr const mp_digit m = (static_cast<mp_digit>(1) << MP_DIGIT_BIT) - 1;
  837. #endif
  838. if (val <= m)
  839. {
  840. mp_digit d;
  841. detail::check_tommath_result(mp_mod_d(const_cast< ::mp_int*>(&x.data()), static_cast<mp_digit>(val), &d));
  842. return d;
  843. }
  844. else
  845. {
  846. return default_ops::eval_integer_modulus(x, val);
  847. }
  848. }
  849. template <class Integer>
  850. inline typename std::enable_if<boost::multiprecision::detail::is_signed<Integer>::value && boost::multiprecision::detail::is_integral<Integer>::value, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
  851. {
  852. return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
  853. }
  854. inline std::size_t hash_value(const tommath_int& val)
  855. {
  856. std::size_t result = 0;
  857. std::size_t len = val.data().used;
  858. for (std::size_t i = 0; i < len; ++i)
  859. boost::multiprecision::detail::hash_combine(result, val.data().dp[i]);
  860. boost::multiprecision::detail::hash_combine(result, val.data().sign);
  861. return result;
  862. }
  863. } // namespace backends
  864. template <>
  865. struct number_category<tommath_int> : public std::integral_constant<int, number_kind_integer>
  866. {};
  867. }
  868. } // namespace boost::multiprecision
  869. namespace std {
  870. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  871. class numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >
  872. {
  873. using number_type = boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates>;
  874. public:
  875. static constexpr bool is_specialized = true;
  876. //
  877. // Largest and smallest numbers are bounded only by available memory, set
  878. // to zero:
  879. //
  880. static number_type(min)()
  881. {
  882. return number_type();
  883. }
  884. static number_type(max)()
  885. {
  886. return number_type();
  887. }
  888. static number_type lowest() { return (min)(); }
  889. static constexpr int digits = INT_MAX;
  890. static constexpr int digits10 = (INT_MAX / 1000) * 301L;
  891. static constexpr int max_digits10 = digits10 + 3;
  892. static constexpr bool is_signed = true;
  893. static constexpr bool is_integer = true;
  894. static constexpr bool is_exact = true;
  895. static constexpr int radix = 2;
  896. static number_type epsilon() { return number_type(); }
  897. static number_type round_error() { return number_type(); }
  898. static constexpr int min_exponent = 0;
  899. static constexpr int min_exponent10 = 0;
  900. static constexpr int max_exponent = 0;
  901. static constexpr int max_exponent10 = 0;
  902. static constexpr bool has_infinity = false;
  903. static constexpr bool has_quiet_NaN = false;
  904. static constexpr bool has_signaling_NaN = false;
  905. static constexpr float_denorm_style has_denorm = denorm_absent;
  906. static constexpr bool has_denorm_loss = false;
  907. static number_type infinity() { return number_type(); }
  908. static number_type quiet_NaN() { return number_type(); }
  909. static number_type signaling_NaN() { return number_type(); }
  910. static number_type denorm_min() { return number_type(); }
  911. static constexpr bool is_iec559 = false;
  912. static constexpr bool is_bounded = false;
  913. static constexpr bool is_modulo = false;
  914. static constexpr bool traps = false;
  915. static constexpr bool tinyness_before = false;
  916. static constexpr float_round_style round_style = round_toward_zero;
  917. };
  918. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  919. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits;
  920. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  921. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits10;
  922. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  923. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_digits10;
  924. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  925. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_signed;
  926. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  927. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_integer;
  928. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  929. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_exact;
  930. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  931. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::radix;
  932. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  933. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent;
  934. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  935. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent10;
  936. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  937. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent;
  938. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  939. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent10;
  940. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  941. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_infinity;
  942. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  943. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_quiet_NaN;
  944. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  945. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_signaling_NaN;
  946. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  947. constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm;
  948. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  949. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm_loss;
  950. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  951. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_iec559;
  952. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  953. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_bounded;
  954. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  955. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_modulo;
  956. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  957. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::traps;
  958. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  959. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::tinyness_before;
  960. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  961. constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::round_style;
  962. } // namespace std
  963. #endif