tommath.hpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  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. // Check against known removed macro that was removed around the same time as type was changed
  423. #ifdef mp_tobinary
  424. int s;
  425. #else
  426. size_t s;
  427. #endif
  428. detail::check_tommath_result(mp_radix_size(const_cast< ::mp_int*>(&m_data), base, &s));
  429. std::unique_ptr<char[]> a(new char[s + 1]);
  430. #ifndef mp_to_binary
  431. detail::check_tommath_result(mp_toradix_n(const_cast< ::mp_int*>(&m_data), a.get(), base, s + 1));
  432. #else
  433. std::size_t written;
  434. detail::check_tommath_result(mp_to_radix(&m_data, a.get(), s + 1, &written, base));
  435. #endif
  436. std::string result = a.get();
  437. if (f & std::ios_base::uppercase)
  438. for (size_t i = 0; i < result.length(); ++i)
  439. result[i] = std::toupper(result[i]);
  440. if ((base != 10) && (f & std::ios_base::showbase))
  441. {
  442. int pos = result[0] == '-' ? 1 : 0;
  443. const char* pp = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
  444. result.insert(static_cast<std::string::size_type>(pos), pp);
  445. }
  446. if ((f & std::ios_base::showpos) && (result[0] != '-'))
  447. result.insert(static_cast<std::string::size_type>(0), 1, '+');
  448. if (((f & std::ios_base::uppercase) == 0) && (base == 16))
  449. {
  450. for (std::size_t i = 0; i < result.size(); ++i)
  451. result[i] = std::tolower(result[i]);
  452. }
  453. return result;
  454. }
  455. ~tommath_int()
  456. {
  457. if (m_data.dp)
  458. mp_clear(&m_data);
  459. }
  460. void negate()
  461. {
  462. BOOST_MP_ASSERT(m_data.dp);
  463. detail::check_tommath_result(mp_neg(&m_data, &m_data));
  464. }
  465. int compare(const tommath_int& o) const
  466. {
  467. BOOST_MP_ASSERT(m_data.dp && o.m_data.dp);
  468. return mp_cmp(const_cast< ::mp_int*>(&m_data), const_cast< ::mp_int*>(&o.m_data));
  469. }
  470. template <class V>
  471. int compare(V v) const
  472. {
  473. tommath_int d;
  474. tommath_int t(*this);
  475. detail::check_tommath_result(mp_shrink(&t.data()));
  476. d = v;
  477. return t.compare(d);
  478. }
  479. ::mp_int& data()
  480. {
  481. BOOST_MP_ASSERT(m_data.dp);
  482. return m_data;
  483. }
  484. const ::mp_int& data() const
  485. {
  486. BOOST_MP_ASSERT(m_data.dp);
  487. return m_data;
  488. }
  489. void swap(tommath_int& o) noexcept
  490. {
  491. mp_exch(&m_data, &o.data());
  492. }
  493. protected:
  494. ::mp_int m_data;
  495. };
  496. #ifndef mp_isneg
  497. #define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
  498. if (SIGN(&x.data())) \
  499. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
  500. #else
  501. #define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
  502. if (mp_isneg(&x.data())) \
  503. BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
  504. #endif
  505. int eval_get_sign(const tommath_int& val);
  506. inline void eval_add(tommath_int& t, const tommath_int& o)
  507. {
  508. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  509. }
  510. inline void eval_subtract(tommath_int& t, const tommath_int& o)
  511. {
  512. detail::check_tommath_result(mp_sub(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  513. }
  514. inline void eval_multiply(tommath_int& t, const tommath_int& o)
  515. {
  516. detail::check_tommath_result(mp_mul(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  517. }
  518. inline void eval_divide(tommath_int& t, const tommath_int& o)
  519. {
  520. using default_ops::eval_is_zero;
  521. tommath_int temp;
  522. if (eval_is_zero(o))
  523. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  524. detail::check_tommath_result(mp_div(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data(), &temp.data()));
  525. }
  526. inline void eval_modulus(tommath_int& t, const tommath_int& o)
  527. {
  528. using default_ops::eval_is_zero;
  529. if (eval_is_zero(o))
  530. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  531. bool neg = eval_get_sign(t) < 0;
  532. bool neg2 = eval_get_sign(o) < 0;
  533. detail::check_tommath_result(mp_mod(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  534. if ((neg != neg2) && (eval_get_sign(t) != 0))
  535. {
  536. t.negate();
  537. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  538. t.negate();
  539. }
  540. else if (neg && (t.compare(o) == 0))
  541. {
  542. mp_zero(&t.data());
  543. }
  544. }
  545. template <class UI>
  546. inline void eval_left_shift(tommath_int& t, UI i)
  547. {
  548. detail::check_tommath_result(mp_mul_2d(&t.data(), static_cast<unsigned>(i), &t.data()));
  549. }
  550. template <class UI>
  551. inline void eval_right_shift(tommath_int& t, UI i)
  552. {
  553. using default_ops::eval_decrement;
  554. using default_ops::eval_increment;
  555. bool neg = eval_get_sign(t) < 0;
  556. tommath_int d;
  557. if (neg)
  558. eval_increment(t);
  559. detail::check_tommath_result(mp_div_2d(&t.data(), static_cast<unsigned>(i), &t.data(), &d.data()));
  560. if (neg)
  561. eval_decrement(t);
  562. }
  563. template <class UI>
  564. inline void eval_left_shift(tommath_int& t, const tommath_int& v, UI i)
  565. {
  566. detail::check_tommath_result(mp_mul_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned>(i), &t.data()));
  567. }
  568. /*
  569. template <class UI>
  570. inline void eval_right_shift(tommath_int& t, const tommath_int& v, UI i)
  571. {
  572. tommath_int d;
  573. detail::check_tommath_result(mp_div_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned long>(i), &t.data(), &d.data()));
  574. }
  575. */
  576. inline void eval_bitwise_and(tommath_int& result, const tommath_int& v)
  577. {
  578. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  579. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  580. detail::check_tommath_result(mp_and(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  581. }
  582. inline void eval_bitwise_or(tommath_int& result, const tommath_int& v)
  583. {
  584. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  585. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  586. detail::check_tommath_result(mp_or(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  587. }
  588. inline void eval_bitwise_xor(tommath_int& result, const tommath_int& v)
  589. {
  590. BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
  591. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  592. detail::check_tommath_result(mp_xor(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
  593. }
  594. inline void eval_add(tommath_int& t, const tommath_int& p, const tommath_int& o)
  595. {
  596. detail::check_tommath_result(mp_add(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  597. }
  598. inline void eval_subtract(tommath_int& t, const tommath_int& p, const tommath_int& o)
  599. {
  600. detail::check_tommath_result(mp_sub(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  601. }
  602. inline void eval_multiply(tommath_int& t, const tommath_int& p, const tommath_int& o)
  603. {
  604. detail::check_tommath_result(mp_mul(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  605. }
  606. inline void eval_divide(tommath_int& t, const tommath_int& p, const tommath_int& o)
  607. {
  608. using default_ops::eval_is_zero;
  609. tommath_int d;
  610. if (eval_is_zero(o))
  611. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  612. detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data(), &d.data()));
  613. }
  614. inline void eval_modulus(tommath_int& t, const tommath_int& p, const tommath_int& o)
  615. {
  616. using default_ops::eval_is_zero;
  617. if (eval_is_zero(o))
  618. BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
  619. bool neg = eval_get_sign(p) < 0;
  620. bool neg2 = eval_get_sign(o) < 0;
  621. detail::check_tommath_result(mp_mod(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
  622. if ((neg != neg2) && (eval_get_sign(t) != 0))
  623. {
  624. t.negate();
  625. detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
  626. t.negate();
  627. }
  628. else if (neg && (t.compare(o) == 0))
  629. {
  630. mp_zero(&t.data());
  631. }
  632. }
  633. inline void eval_bitwise_and(tommath_int& result, const tommath_int& u, const tommath_int& v)
  634. {
  635. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  636. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  637. detail::check_tommath_result(mp_and(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  638. }
  639. inline void eval_bitwise_or(tommath_int& result, const tommath_int& u, const tommath_int& v)
  640. {
  641. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  642. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  643. detail::check_tommath_result(mp_or(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  644. }
  645. inline void eval_bitwise_xor(tommath_int& result, const tommath_int& u, const tommath_int& v)
  646. {
  647. BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
  648. BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
  649. detail::check_tommath_result(mp_xor(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
  650. }
  651. /*
  652. inline void eval_complement(tommath_int& result, const tommath_int& u)
  653. {
  654. //
  655. // Although this code works, it doesn't really do what the user might expect....
  656. // and it's hard to see how it ever could. Disabled for now:
  657. //
  658. result = u;
  659. for(int i = 0; i < result.data().used; ++i)
  660. {
  661. result.data().dp[i] = MP_MASK & ~(result.data().dp[i]);
  662. }
  663. //
  664. // We now need to pad out the left of the value with 1's to round up to a whole number of
  665. // CHAR_BIT * sizeof(mp_digit) units. Otherwise we'll end up with a very strange number of
  666. // bits set!
  667. //
  668. unsigned shift = result.data().used * DIGIT_BIT; // How many bits we're actually using
  669. // How many bits we actually need, reduced by one to account for a mythical sign bit:
  670. int padding = result.data().used * std::numeric_limits<mp_digit>::digits - shift - 1;
  671. while(padding >= std::numeric_limits<mp_digit>::digits)
  672. padding -= std::numeric_limits<mp_digit>::digits;
  673. // Create a mask providing the extra bits we need and add to result:
  674. tommath_int mask;
  675. mask = static_cast<long long>((1u << padding) - 1);
  676. eval_left_shift(mask, shift);
  677. add(result, mask);
  678. }
  679. */
  680. inline bool eval_is_zero(const tommath_int& val)
  681. {
  682. return mp_iszero(&val.data());
  683. }
  684. inline int eval_get_sign(const tommath_int& val)
  685. {
  686. #ifndef mp_isneg
  687. return mp_iszero(&val.data()) ? 0 : SIGN(&val.data()) ? -1 : 1;
  688. #else
  689. return mp_iszero(&val.data()) ? 0 : mp_isneg(&val.data()) ? -1 : 1;
  690. #endif
  691. }
  692. inline void eval_convert_to(unsigned long long* result, const tommath_int& val)
  693. {
  694. if (mp_isneg(&val.data()))
  695. {
  696. BOOST_MP_THROW_EXCEPTION(std::range_error("Converting negative arbitrary precision value to unsigned."));
  697. }
  698. #ifdef MP_DEPRECATED
  699. *result = mp_get_ull(&val.data());
  700. #else
  701. *result = mp_get_long_long(const_cast<mp_int*>(&val.data()));
  702. #endif
  703. }
  704. inline void eval_convert_to(long long* result, const tommath_int& val)
  705. {
  706. if (!mp_iszero(&val.data()) && (mp_count_bits(const_cast<::mp_int*>(&val.data())) > std::numeric_limits<long long>::digits))
  707. {
  708. *result = mp_isneg(&val.data()) ? (std::numeric_limits<long long>::min)() : (std::numeric_limits<long long>::max)();
  709. return;
  710. }
  711. #ifdef MP_DEPRECATED
  712. unsigned long long r = mp_get_mag_ull(&val.data());
  713. #else
  714. unsigned long long r = mp_get_long_long(const_cast<mp_int*>(&val.data()));
  715. #endif
  716. if (mp_isneg(&val.data()))
  717. *result = -static_cast<long long>(r);
  718. else
  719. *result = r;
  720. }
  721. #ifdef BOOST_HAS_INT128
  722. inline void eval_convert_to(uint128_type* result, const tommath_int& val)
  723. {
  724. #ifdef MP_DEPRECATED
  725. if (mp_ubin_size(&val.data()) > sizeof(uint128_type))
  726. {
  727. *result = ~static_cast<uint128_type>(0);
  728. return;
  729. }
  730. unsigned char buf[sizeof(uint128_type)];
  731. std::size_t len;
  732. detail::check_tommath_result(mp_to_ubin(&val.data(), buf, sizeof(buf), &len));
  733. *result = 0;
  734. for (std::size_t i = 0; i < len; ++i)
  735. {
  736. *result <<= CHAR_BIT;
  737. *result |= buf[i];
  738. }
  739. #else
  740. std::size_t len = mp_unsigned_bin_size(const_cast<mp_int*>(&val.data()));
  741. if (len > sizeof(uint128_type))
  742. {
  743. *result = ~static_cast<uint128_type>(0);
  744. return;
  745. }
  746. unsigned char buf[sizeof(uint128_type)];
  747. detail::check_tommath_result(mp_to_unsigned_bin(const_cast<mp_int*>(&val.data()), buf));
  748. *result = 0;
  749. for (std::size_t i = 0; i < len; ++i)
  750. {
  751. *result <<= CHAR_BIT;
  752. *result |= buf[i];
  753. }
  754. #endif
  755. }
  756. inline void eval_convert_to(int128_type* result, const tommath_int& val)
  757. {
  758. uint128_type r;
  759. eval_convert_to(&r, val);
  760. if (mp_isneg(&val.data()))
  761. *result = -static_cast<int128_type>(r);
  762. else
  763. *result = r;
  764. }
  765. #endif
  766. #if defined(BOOST_HAS_FLOAT128)
  767. inline void eval_convert_to(float128_type* result, const tommath_int& val) noexcept
  768. {
  769. *result = float128_procs::strtoflt128(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  770. }
  771. #endif
  772. inline void eval_convert_to(long double* result, const tommath_int& val) noexcept
  773. {
  774. *result = std::strtold(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  775. }
  776. inline void eval_convert_to(double* result, const tommath_int& val) noexcept
  777. {
  778. *result = std::strtod(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  779. }
  780. inline void eval_convert_to(float* result, const tommath_int& val) noexcept
  781. {
  782. *result = std::strtof(val.str(0, std::ios_base::scientific).c_str(), nullptr);
  783. }
  784. inline void eval_abs(tommath_int& result, const tommath_int& val)
  785. {
  786. detail::check_tommath_result(mp_abs(const_cast< ::mp_int*>(&val.data()), &result.data()));
  787. }
  788. inline void eval_gcd(tommath_int& result, const tommath_int& a, const tommath_int& b)
  789. {
  790. detail::check_tommath_result(mp_gcd(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
  791. }
  792. inline void eval_lcm(tommath_int& result, const tommath_int& a, const tommath_int& b)
  793. {
  794. detail::check_tommath_result(mp_lcm(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
  795. }
  796. inline void eval_powm(tommath_int& result, const tommath_int& base, const tommath_int& p, const tommath_int& m)
  797. {
  798. if (eval_get_sign(p) < 0)
  799. {
  800. BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
  801. }
  802. 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()));
  803. }
  804. inline void eval_qr(const tommath_int& x, const tommath_int& y,
  805. tommath_int& q, tommath_int& r)
  806. {
  807. detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&x.data()), const_cast< ::mp_int*>(&y.data()), &q.data(), &r.data()));
  808. }
  809. inline std::size_t eval_lsb(const tommath_int& val)
  810. {
  811. int c = eval_get_sign(val);
  812. if (c == 0)
  813. {
  814. BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
  815. }
  816. if (c < 0)
  817. {
  818. BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
  819. }
  820. return mp_cnt_lsb(const_cast< ::mp_int*>(&val.data()));
  821. }
  822. inline std::size_t eval_msb(const tommath_int& val)
  823. {
  824. int c = eval_get_sign(val);
  825. if (c == 0)
  826. {
  827. BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
  828. }
  829. if (c < 0)
  830. {
  831. BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
  832. }
  833. return mp_count_bits(const_cast< ::mp_int*>(&val.data())) - 1;
  834. }
  835. template <class Integer>
  836. inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
  837. {
  838. #ifndef MP_DIGIT_BIT
  839. constexpr const mp_digit m = (static_cast<mp_digit>(1) << DIGIT_BIT) - 1;
  840. #else
  841. constexpr const mp_digit m = (static_cast<mp_digit>(1) << MP_DIGIT_BIT) - 1;
  842. #endif
  843. if (val <= m)
  844. {
  845. mp_digit d;
  846. detail::check_tommath_result(mp_mod_d(const_cast< ::mp_int*>(&x.data()), static_cast<mp_digit>(val), &d));
  847. return d;
  848. }
  849. else
  850. {
  851. return default_ops::eval_integer_modulus(x, val);
  852. }
  853. }
  854. template <class Integer>
  855. 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)
  856. {
  857. return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
  858. }
  859. inline std::size_t hash_value(const tommath_int& val)
  860. {
  861. std::size_t result = 0;
  862. std::size_t len = val.data().used;
  863. for (std::size_t i = 0; i < len; ++i)
  864. boost::multiprecision::detail::hash_combine(result, val.data().dp[i]);
  865. boost::multiprecision::detail::hash_combine(result, val.data().sign);
  866. return result;
  867. }
  868. } // namespace backends
  869. template <>
  870. struct number_category<tommath_int> : public std::integral_constant<int, number_kind_integer>
  871. {};
  872. }
  873. } // namespace boost::multiprecision
  874. namespace std {
  875. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  876. class numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >
  877. {
  878. using number_type = boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates>;
  879. public:
  880. static constexpr bool is_specialized = true;
  881. //
  882. // Largest and smallest numbers are bounded only by available memory, set
  883. // to zero:
  884. //
  885. static number_type(min)()
  886. {
  887. return number_type();
  888. }
  889. static number_type(max)()
  890. {
  891. return number_type();
  892. }
  893. static number_type lowest() { return (min)(); }
  894. static constexpr int digits = INT_MAX;
  895. static constexpr int digits10 = (INT_MAX / 1000) * 301L;
  896. static constexpr int max_digits10 = digits10 + 3;
  897. static constexpr bool is_signed = true;
  898. static constexpr bool is_integer = true;
  899. static constexpr bool is_exact = true;
  900. static constexpr int radix = 2;
  901. static number_type epsilon() { return number_type(); }
  902. static number_type round_error() { return number_type(); }
  903. static constexpr int min_exponent = 0;
  904. static constexpr int min_exponent10 = 0;
  905. static constexpr int max_exponent = 0;
  906. static constexpr int max_exponent10 = 0;
  907. static constexpr bool has_infinity = false;
  908. static constexpr bool has_quiet_NaN = false;
  909. static constexpr bool has_signaling_NaN = false;
  910. #ifdef _MSC_VER
  911. #pragma warning(push)
  912. #pragma warning(disable : 4996)
  913. #endif
  914. static constexpr float_denorm_style has_denorm = denorm_absent;
  915. #ifdef _MSC_VER
  916. #pragma warning(pop)
  917. #endif
  918. static constexpr bool has_denorm_loss = false;
  919. static number_type infinity() { return number_type(); }
  920. static number_type quiet_NaN() { return number_type(); }
  921. static number_type signaling_NaN() { return number_type(); }
  922. static number_type denorm_min() { return number_type(); }
  923. static constexpr bool is_iec559 = false;
  924. static constexpr bool is_bounded = false;
  925. static constexpr bool is_modulo = false;
  926. static constexpr bool traps = false;
  927. static constexpr bool tinyness_before = false;
  928. static constexpr float_round_style round_style = round_toward_zero;
  929. };
  930. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  931. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits;
  932. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  933. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits10;
  934. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  935. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_digits10;
  936. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  937. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_signed;
  938. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  939. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_integer;
  940. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  941. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_exact;
  942. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  943. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::radix;
  944. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  945. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent;
  946. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  947. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent10;
  948. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  949. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent;
  950. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  951. constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent10;
  952. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  953. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_infinity;
  954. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  955. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_quiet_NaN;
  956. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  957. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_signaling_NaN;
  958. #ifdef _MSC_VER
  959. #pragma warning(push)
  960. #pragma warning(disable : 4996)
  961. #endif
  962. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  963. constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm;
  964. #ifdef _MSC_VER
  965. #pragma warning(pop)
  966. #endif
  967. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  968. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm_loss;
  969. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  970. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_iec559;
  971. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  972. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_bounded;
  973. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  974. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_modulo;
  975. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  976. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::traps;
  977. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  978. constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::tinyness_before;
  979. template <boost::multiprecision::expression_template_option ExpressionTemplates>
  980. constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::round_style;
  981. } // namespace std
  982. #endif