File indexing completed on 2025-01-18 09:42:38
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MP_TOMMATH_HPP
0008 #define BOOST_MP_TOMMATH_HPP
0009
0010 #include <cctype>
0011 #include <climits>
0012 #include <cmath>
0013 #include <cstdint>
0014 #include <cstddef>
0015 #include <cstdlib>
0016 #include <limits>
0017 #include <memory>
0018 #include <string>
0019
0020 #include <tommath.h>
0021
0022 #include <boost/multiprecision/detail/standalone_config.hpp>
0023 #include <boost/multiprecision/detail/fpclassify.hpp>
0024 #include <boost/multiprecision/number.hpp>
0025 #include <boost/multiprecision/rational_adaptor.hpp>
0026 #include <boost/multiprecision/detail/integer_ops.hpp>
0027 #include <boost/multiprecision/detail/hash.hpp>
0028 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0029 #include <boost/multiprecision/detail/assert.hpp>
0030
0031 namespace boost {
0032 namespace multiprecision {
0033 namespace backends {
0034
0035 namespace detail {
0036
0037 template <class ErrType>
0038 inline void check_tommath_result(ErrType v)
0039 {
0040 if (v != MP_OKAY)
0041 {
0042 BOOST_MP_THROW_EXCEPTION(std::runtime_error(mp_error_to_string(v)));
0043 }
0044 }
0045
0046 }
0047
0048 void eval_multiply(tommath_int& t, const tommath_int& o);
0049 void eval_add(tommath_int& t, const tommath_int& o);
0050
0051 struct tommath_int
0052 {
0053 using signed_types = std::tuple<std::int32_t, long long> ;
0054 using unsigned_types = std::tuple<std::uint32_t, unsigned long long>;
0055 using float_types = std::tuple<long double> ;
0056
0057 tommath_int()
0058 {
0059 detail::check_tommath_result(mp_init(&m_data));
0060 }
0061 tommath_int(const tommath_int& o)
0062 {
0063 detail::check_tommath_result(mp_init_copy(&m_data, const_cast< ::mp_int*>(&o.m_data)));
0064 }
0065
0066 tommath_int(tommath_int&& o) noexcept
0067 {
0068 m_data = o.m_data;
0069 o.m_data.dp = 0;
0070 }
0071 tommath_int& operator=(tommath_int&& o)
0072 {
0073 mp_exch(&m_data, &o.m_data);
0074 return *this;
0075 }
0076 tommath_int& operator=(const tommath_int& o)
0077 {
0078 if (m_data.dp == nullptr)
0079 detail::check_tommath_result(mp_init(&m_data));
0080 if (o.m_data.dp)
0081 detail::check_tommath_result(mp_copy(const_cast< ::mp_int*>(&o.m_data), &m_data));
0082 return *this;
0083 }
0084 #ifndef mp_get_u64
0085
0086 tommath_int& operator=(unsigned long long i)
0087 {
0088 if (m_data.dp == nullptr)
0089 detail::check_tommath_result(mp_init(&m_data));
0090 unsigned long long mask = ((1uLL << 32) - 1);
0091 unsigned shift = 0;
0092 ::mp_int t;
0093 detail::check_tommath_result(mp_init(&t));
0094 mp_zero(&m_data);
0095 while (i)
0096 {
0097 detail::check_tommath_result(mp_set_int(&t, static_cast<unsigned>(i & mask)));
0098 if (shift)
0099 detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
0100 detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
0101 shift += 32;
0102 i >>= 32;
0103 }
0104 mp_clear(&t);
0105 return *this;
0106 }
0107 #elif !defined(ULLONG_MAX) || (ULLONG_MAX != 18446744073709551615uLL)
0108
0109 tommath_int& operator=(unsigned long long i)
0110 {
0111 if (m_data.dp == nullptr)
0112 detail::check_tommath_result(mp_init(&m_data));
0113 if(sizeof(unsigned long long) * CHAR_BIT == 64)
0114 {
0115 mp_set_u64(&m_data, i);
0116 return *this;
0117 }
0118 unsigned long long mask = ((1uLL << 64) - 1);
0119 unsigned shift = 0;
0120 ::mp_int t;
0121 detail::check_tommath_result(mp_init(&t));
0122 mp_zero(&m_data);
0123 while (i)
0124 {
0125 detail::check_tommath_result(mp_set_u64(&t, static_cast<std::uint64_t>(i & mask)));
0126 if (shift)
0127 detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
0128 detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
0129 shift += 64;
0130 i >>= 64;
0131 }
0132 mp_clear(&t);
0133 return *this;
0134 }
0135 #else
0136 tommath_int& operator=(unsigned long long i)
0137 {
0138 if (m_data.dp == nullptr)
0139 detail::check_tommath_result(mp_init(&m_data));
0140 mp_set_u64(&m_data, i);
0141 return *this;
0142 }
0143 #endif
0144 tommath_int& operator=(long long i)
0145 {
0146 if (m_data.dp == nullptr)
0147 detail::check_tommath_result(mp_init(&m_data));
0148 bool neg = i < 0;
0149 *this = boost::multiprecision::detail::unsigned_abs(i);
0150 if (neg)
0151 detail::check_tommath_result(mp_neg(&m_data, &m_data));
0152 return *this;
0153 }
0154 #ifdef BOOST_HAS_INT128
0155
0156 tommath_int& operator=(uint128_type i)
0157 {
0158 if (m_data.dp == nullptr)
0159 detail::check_tommath_result(mp_init(&m_data));
0160
0161 int128_type mask = ((static_cast<uint128_type>(1u) << 64) - 1);
0162 unsigned shift = 0;
0163 ::mp_int t;
0164 detail::check_tommath_result(mp_init(&t));
0165 mp_zero(&m_data);
0166 while (i)
0167 {
0168 #ifndef mp_get_u32
0169 detail::check_tommath_result(mp_set_long_long(&t, static_cast<std::uint64_t>(i & mask)));
0170 #else
0171 mp_set_u64(&t, static_cast<std::uint64_t>(i & mask));
0172 #endif
0173 if (shift)
0174 detail::check_tommath_result(mp_mul_2d(&t, shift, &t));
0175 detail::check_tommath_result((mp_add(&m_data, &t, &m_data)));
0176 shift += 64;
0177 i >>= 64;
0178 }
0179 mp_clear(&t);
0180 return *this;
0181 }
0182 tommath_int& operator=(int128_type i)
0183 {
0184 if (m_data.dp == nullptr)
0185 detail::check_tommath_result(mp_init(&m_data));
0186 bool neg = i < 0;
0187 *this = boost::multiprecision::detail::unsigned_abs(i);
0188 if (neg)
0189 detail::check_tommath_result(mp_neg(&m_data, &m_data));
0190 return *this;
0191 }
0192 #endif
0193
0194
0195
0196
0197
0198 tommath_int& operator=(std::uint32_t i)
0199 {
0200 if (m_data.dp == nullptr)
0201 detail::check_tommath_result(mp_init(&m_data));
0202 #ifndef mp_get_u32
0203 detail::check_tommath_result((mp_set_int(&m_data, i)));
0204 #else
0205 mp_set_u32(&m_data, i);
0206 #endif
0207 return *this;
0208 }
0209 tommath_int& operator=(std::int32_t i)
0210 {
0211 if (m_data.dp == nullptr)
0212 detail::check_tommath_result(mp_init(&m_data));
0213 bool neg = i < 0;
0214 *this = boost::multiprecision::detail::unsigned_abs(i);
0215 if (neg)
0216 detail::check_tommath_result(mp_neg(&m_data, &m_data));
0217 return *this;
0218 }
0219 template <class F>
0220 tommath_int& assign_float(F a)
0221 {
0222 BOOST_MP_FLOAT128_USING using std::floor; using std::frexp; using std::ldexp;
0223
0224 if (m_data.dp == nullptr)
0225 detail::check_tommath_result(mp_init(&m_data));
0226
0227 if (a == 0)
0228 {
0229 #ifndef mp_get_u32
0230 detail::check_tommath_result(mp_set_int(&m_data, 0));
0231 #else
0232 mp_set_i32(&m_data, 0);
0233 #endif
0234 return *this;
0235 }
0236
0237 if (a == 1)
0238 {
0239 #ifndef mp_get_u32
0240 detail::check_tommath_result(mp_set_int(&m_data, 1));
0241 #else
0242 mp_set_i32(&m_data, 1);
0243 #endif
0244 return *this;
0245 }
0246
0247 BOOST_MP_ASSERT(!BOOST_MP_ISINF(a));
0248 BOOST_MP_ASSERT(!BOOST_MP_ISNAN(a));
0249
0250 int e;
0251 F f, term;
0252 #ifndef mp_get_u32
0253 detail::check_tommath_result(mp_set_int(&m_data, 0u));
0254 #else
0255 mp_set_i32(&m_data, 0);
0256 #endif
0257 ::mp_int t;
0258 detail::check_tommath_result(mp_init(&t));
0259
0260 f = frexp(a, &e);
0261
0262 #ifdef MP_DIGIT_BIT
0263 constexpr const int shift = std::numeric_limits<int>::digits - 1;
0264 using part_type = int ;
0265 #else
0266 constexpr const int shift = std::numeric_limits<std::int64_t>::digits - 1;
0267 using part_type = std::int64_t;
0268 #endif
0269
0270 while (f)
0271 {
0272
0273 f = ldexp(f, shift);
0274 term = floor(f);
0275 e -= shift;
0276 detail::check_tommath_result(mp_mul_2d(&m_data, shift, &m_data));
0277 if (term > 0)
0278 {
0279 #ifndef mp_get_u64
0280 detail::check_tommath_result(mp_set_int(&t, static_cast<part_type>(term)));
0281 #else
0282 mp_set_i64(&t, static_cast<part_type>(term));
0283 #endif
0284 detail::check_tommath_result(mp_add(&m_data, &t, &m_data));
0285 }
0286 else
0287 {
0288 #ifndef mp_get_u64
0289 detail::check_tommath_result(mp_set_int(&t, static_cast<part_type>(-term)));
0290 #else
0291 mp_set_i64(&t, static_cast<part_type>(-term));
0292 #endif
0293 detail::check_tommath_result(mp_sub(&m_data, &t, &m_data));
0294 }
0295 f -= term;
0296 }
0297 if (e > 0)
0298 detail::check_tommath_result(mp_mul_2d(&m_data, e, &m_data));
0299 else if (e < 0)
0300 {
0301 tommath_int t2;
0302 detail::check_tommath_result(mp_div_2d(&m_data, -e, &m_data, &t2.data()));
0303 }
0304 mp_clear(&t);
0305 return *this;
0306 }
0307 tommath_int& operator=(long double a)
0308 {
0309 return assign_float(a);
0310 }
0311 #ifdef BOOST_HAS_FLOAT128
0312 tommath_int& operator= (float128_type a)
0313 {
0314 return assign_float(a);
0315 }
0316 #endif
0317 tommath_int& operator=(const char* s)
0318 {
0319
0320
0321
0322 if (m_data.dp == nullptr)
0323 detail::check_tommath_result(mp_init(&m_data));
0324 std::size_t n = s ? std::strlen(s) : 0;
0325 *this = static_cast<std::uint32_t>(0u);
0326 unsigned radix = 10;
0327 bool isneg = false;
0328 if (n && (*s == '-'))
0329 {
0330 --n;
0331 ++s;
0332 isneg = true;
0333 }
0334 if (n && (*s == '0'))
0335 {
0336 if ((n > 1) && ((s[1] == 'x') || (s[1] == 'X')))
0337 {
0338 radix = 16;
0339 s += 2;
0340 n -= 2;
0341 }
0342 else
0343 {
0344 radix = 8;
0345 n -= 1;
0346 }
0347 }
0348 if (n)
0349 {
0350 if (radix == 8 || radix == 16)
0351 {
0352 unsigned shift = radix == 8 ? 3 : 4;
0353 #ifndef MP_DIGIT_BIT
0354 unsigned block_count = DIGIT_BIT / shift;
0355 #else
0356 unsigned block_count = MP_DIGIT_BIT / shift;
0357 #endif
0358 unsigned block_shift = shift * block_count;
0359 unsigned long long val, block;
0360 while (*s)
0361 {
0362 block = 0;
0363 for (unsigned i = 0; (i < block_count); ++i)
0364 {
0365 if (*s >= '0' && *s <= '9')
0366 val = *s - '0';
0367 else if (*s >= 'a' && *s <= 'f')
0368 val = 10 + *s - 'a';
0369 else if (*s >= 'A' && *s <= 'F')
0370 val = 10 + *s - 'A';
0371 else
0372 val = 400;
0373 if (val > radix)
0374 {
0375 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Unexpected content found while parsing character string."));
0376 }
0377 block <<= shift;
0378 block |= val;
0379 if (!*++s)
0380 {
0381
0382 block_shift = (i + 1) * shift;
0383 break;
0384 }
0385 }
0386 detail::check_tommath_result(mp_mul_2d(&data(), block_shift, &data()));
0387 if (data().used)
0388 data().dp[0] |= block;
0389 else
0390 *this = block;
0391 }
0392 }
0393 else
0394 {
0395
0396
0397 std::uint32_t block_mult = 1000000000;
0398 while (*s)
0399 {
0400 std::uint32_t block = 0;
0401 for (unsigned i = 0; i < 9; ++i)
0402 {
0403 std::uint32_t val;
0404 if (*s >= '0' && *s <= '9')
0405 val = *s - '0';
0406 else
0407 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Unexpected character encountered in input."));
0408 block *= 10;
0409 block += val;
0410 if (!*++s)
0411 {
0412 constexpr const std::uint32_t block_multiplier[9] = {10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
0413 block_mult = block_multiplier[i];
0414 break;
0415 }
0416 }
0417 tommath_int t;
0418 t = block_mult;
0419 eval_multiply(*this, t);
0420 t = block;
0421 eval_add(*this, t);
0422 }
0423 }
0424 }
0425 if (isneg)
0426 this->negate();
0427 return *this;
0428 }
0429 std::string str(std::streamsize , std::ios_base::fmtflags f) const
0430 {
0431 BOOST_MP_ASSERT(m_data.dp);
0432 int base = 10;
0433 if ((f & std::ios_base::oct) == std::ios_base::oct)
0434 base = 8;
0435 else if ((f & std::ios_base::hex) == std::ios_base::hex)
0436 base = 16;
0437
0438
0439
0440 if ((base != 10) && m_data.sign)
0441 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Formatted output in bases 8 or 16 is only available for positive numbers"));
0442
0443 int s;
0444 detail::check_tommath_result(mp_radix_size(const_cast< ::mp_int*>(&m_data), base, &s));
0445 std::unique_ptr<char[]> a(new char[s + 1]);
0446 #ifndef mp_to_binary
0447 detail::check_tommath_result(mp_toradix_n(const_cast< ::mp_int*>(&m_data), a.get(), base, s + 1));
0448 #else
0449 std::size_t written;
0450 detail::check_tommath_result(mp_to_radix(&m_data, a.get(), s + 1, &written, base));
0451 #endif
0452 std::string result = a.get();
0453 if (f & std::ios_base::uppercase)
0454 for (size_t i = 0; i < result.length(); ++i)
0455 result[i] = std::toupper(result[i]);
0456 if ((base != 10) && (f & std::ios_base::showbase))
0457 {
0458 int pos = result[0] == '-' ? 1 : 0;
0459 const char* pp = base == 8 ? "0" : (f & std::ios_base::uppercase) ? "0X" : "0x";
0460 result.insert(static_cast<std::string::size_type>(pos), pp);
0461 }
0462 if ((f & std::ios_base::showpos) && (result[0] != '-'))
0463 result.insert(static_cast<std::string::size_type>(0), 1, '+');
0464 if (((f & std::ios_base::uppercase) == 0) && (base == 16))
0465 {
0466 for (std::size_t i = 0; i < result.size(); ++i)
0467 result[i] = std::tolower(result[i]);
0468 }
0469 return result;
0470 }
0471 ~tommath_int()
0472 {
0473 if (m_data.dp)
0474 mp_clear(&m_data);
0475 }
0476 void negate()
0477 {
0478 BOOST_MP_ASSERT(m_data.dp);
0479 detail::check_tommath_result(mp_neg(&m_data, &m_data));
0480 }
0481 int compare(const tommath_int& o) const
0482 {
0483 BOOST_MP_ASSERT(m_data.dp && o.m_data.dp);
0484 return mp_cmp(const_cast< ::mp_int*>(&m_data), const_cast< ::mp_int*>(&o.m_data));
0485 }
0486 template <class V>
0487 int compare(V v) const
0488 {
0489 tommath_int d;
0490 tommath_int t(*this);
0491 detail::check_tommath_result(mp_shrink(&t.data()));
0492 d = v;
0493 return t.compare(d);
0494 }
0495 ::mp_int& data()
0496 {
0497 BOOST_MP_ASSERT(m_data.dp);
0498 return m_data;
0499 }
0500 const ::mp_int& data() const
0501 {
0502 BOOST_MP_ASSERT(m_data.dp);
0503 return m_data;
0504 }
0505 void swap(tommath_int& o) noexcept
0506 {
0507 mp_exch(&m_data, &o.data());
0508 }
0509
0510 protected:
0511 ::mp_int m_data;
0512 };
0513
0514 #ifndef mp_isneg
0515 #define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
0516 if (SIGN(&x.data())) \
0517 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
0518 #else
0519 #define BOOST_MP_TOMMATH_BIT_OP_CHECK(x) \
0520 if (mp_isneg(&x.data())) \
0521 BOOST_MP_THROW_EXCEPTION(std::runtime_error("Bitwise operations on libtommath negative valued integers are disabled as they produce unpredictable results"))
0522 #endif
0523
0524 int eval_get_sign(const tommath_int& val);
0525
0526 inline void eval_add(tommath_int& t, const tommath_int& o)
0527 {
0528 detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
0529 }
0530 inline void eval_subtract(tommath_int& t, const tommath_int& o)
0531 {
0532 detail::check_tommath_result(mp_sub(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
0533 }
0534 inline void eval_multiply(tommath_int& t, const tommath_int& o)
0535 {
0536 detail::check_tommath_result(mp_mul(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
0537 }
0538 inline void eval_divide(tommath_int& t, const tommath_int& o)
0539 {
0540 using default_ops::eval_is_zero;
0541 tommath_int temp;
0542 if (eval_is_zero(o))
0543 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
0544 detail::check_tommath_result(mp_div(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data(), &temp.data()));
0545 }
0546 inline void eval_modulus(tommath_int& t, const tommath_int& o)
0547 {
0548 using default_ops::eval_is_zero;
0549 if (eval_is_zero(o))
0550 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
0551 bool neg = eval_get_sign(t) < 0;
0552 bool neg2 = eval_get_sign(o) < 0;
0553 detail::check_tommath_result(mp_mod(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
0554 if ((neg != neg2) && (eval_get_sign(t) != 0))
0555 {
0556 t.negate();
0557 detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
0558 t.negate();
0559 }
0560 else if (neg && (t.compare(o) == 0))
0561 {
0562 mp_zero(&t.data());
0563 }
0564 }
0565 template <class UI>
0566 inline void eval_left_shift(tommath_int& t, UI i)
0567 {
0568 detail::check_tommath_result(mp_mul_2d(&t.data(), static_cast<unsigned>(i), &t.data()));
0569 }
0570 template <class UI>
0571 inline void eval_right_shift(tommath_int& t, UI i)
0572 {
0573 using default_ops::eval_decrement;
0574 using default_ops::eval_increment;
0575 bool neg = eval_get_sign(t) < 0;
0576 tommath_int d;
0577 if (neg)
0578 eval_increment(t);
0579 detail::check_tommath_result(mp_div_2d(&t.data(), static_cast<unsigned>(i), &t.data(), &d.data()));
0580 if (neg)
0581 eval_decrement(t);
0582 }
0583 template <class UI>
0584 inline void eval_left_shift(tommath_int& t, const tommath_int& v, UI i)
0585 {
0586 detail::check_tommath_result(mp_mul_2d(const_cast< ::mp_int*>(&v.data()), static_cast<unsigned>(i), &t.data()));
0587 }
0588
0589
0590
0591
0592
0593
0594
0595
0596 inline void eval_bitwise_and(tommath_int& result, const tommath_int& v)
0597 {
0598 BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
0599 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
0600 detail::check_tommath_result(mp_and(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
0601 }
0602
0603 inline void eval_bitwise_or(tommath_int& result, const tommath_int& v)
0604 {
0605 BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
0606 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
0607 detail::check_tommath_result(mp_or(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
0608 }
0609
0610 inline void eval_bitwise_xor(tommath_int& result, const tommath_int& v)
0611 {
0612 BOOST_MP_TOMMATH_BIT_OP_CHECK(result);
0613 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
0614 detail::check_tommath_result(mp_xor(&result.data(), const_cast< ::mp_int*>(&v.data()), &result.data()));
0615 }
0616
0617 inline void eval_add(tommath_int& t, const tommath_int& p, const tommath_int& o)
0618 {
0619 detail::check_tommath_result(mp_add(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
0620 }
0621 inline void eval_subtract(tommath_int& t, const tommath_int& p, const tommath_int& o)
0622 {
0623 detail::check_tommath_result(mp_sub(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
0624 }
0625 inline void eval_multiply(tommath_int& t, const tommath_int& p, const tommath_int& o)
0626 {
0627 detail::check_tommath_result(mp_mul(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
0628 }
0629 inline void eval_divide(tommath_int& t, const tommath_int& p, const tommath_int& o)
0630 {
0631 using default_ops::eval_is_zero;
0632 tommath_int d;
0633 if (eval_is_zero(o))
0634 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
0635 detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data(), &d.data()));
0636 }
0637 inline void eval_modulus(tommath_int& t, const tommath_int& p, const tommath_int& o)
0638 {
0639 using default_ops::eval_is_zero;
0640 if (eval_is_zero(o))
0641 BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer division by zero"));
0642 bool neg = eval_get_sign(p) < 0;
0643 bool neg2 = eval_get_sign(o) < 0;
0644 detail::check_tommath_result(mp_mod(const_cast< ::mp_int*>(&p.data()), const_cast< ::mp_int*>(&o.data()), &t.data()));
0645 if ((neg != neg2) && (eval_get_sign(t) != 0))
0646 {
0647 t.negate();
0648 detail::check_tommath_result(mp_add(&t.data(), const_cast< ::mp_int*>(&o.data()), &t.data()));
0649 t.negate();
0650 }
0651 else if (neg && (t.compare(o) == 0))
0652 {
0653 mp_zero(&t.data());
0654 }
0655 }
0656
0657 inline void eval_bitwise_and(tommath_int& result, const tommath_int& u, const tommath_int& v)
0658 {
0659 BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
0660 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
0661 detail::check_tommath_result(mp_and(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
0662 }
0663
0664 inline void eval_bitwise_or(tommath_int& result, const tommath_int& u, const tommath_int& v)
0665 {
0666 BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
0667 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
0668 detail::check_tommath_result(mp_or(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
0669 }
0670
0671 inline void eval_bitwise_xor(tommath_int& result, const tommath_int& u, const tommath_int& v)
0672 {
0673 BOOST_MP_TOMMATH_BIT_OP_CHECK(u);
0674 BOOST_MP_TOMMATH_BIT_OP_CHECK(v);
0675 detail::check_tommath_result(mp_xor(const_cast< ::mp_int*>(&u.data()), const_cast< ::mp_int*>(&v.data()), &result.data()));
0676 }
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707 inline bool eval_is_zero(const tommath_int& val)
0708 {
0709 return mp_iszero(&val.data());
0710 }
0711 inline int eval_get_sign(const tommath_int& val)
0712 {
0713 #ifndef mp_isneg
0714 return mp_iszero(&val.data()) ? 0 : SIGN(&val.data()) ? -1 : 1;
0715 #else
0716 return mp_iszero(&val.data()) ? 0 : mp_isneg(&val.data()) ? -1 : 1;
0717 #endif
0718 }
0719
0720 inline void eval_convert_to(unsigned long long* result, const tommath_int& val)
0721 {
0722 if (mp_isneg(&val.data()))
0723 {
0724 BOOST_MP_THROW_EXCEPTION(std::range_error("Converting negative arbitrary precision value to unsigned."));
0725 }
0726 #ifdef MP_DEPRECATED
0727 *result = mp_get_ull(&val.data());
0728 #else
0729 *result = mp_get_long_long(const_cast<mp_int*>(&val.data()));
0730 #endif
0731 }
0732
0733 inline void eval_convert_to(long long* result, const tommath_int& val)
0734 {
0735 if (!mp_iszero(&val.data()) && (mp_count_bits(const_cast<::mp_int*>(&val.data())) > std::numeric_limits<long long>::digits))
0736 {
0737 *result = mp_isneg(&val.data()) ? (std::numeric_limits<long long>::min)() : (std::numeric_limits<long long>::max)();
0738 return;
0739 }
0740 #ifdef MP_DEPRECATED
0741 unsigned long long r = mp_get_mag_ull(&val.data());
0742 #else
0743 unsigned long long r = mp_get_long_long(const_cast<mp_int*>(&val.data()));
0744 #endif
0745 if (mp_isneg(&val.data()))
0746 *result = -static_cast<long long>(r);
0747 else
0748 *result = r;
0749 }
0750
0751 #ifdef BOOST_HAS_INT128
0752 inline void eval_convert_to(uint128_type* result, const tommath_int& val)
0753 {
0754 #ifdef MP_DEPRECATED
0755 if (mp_ubin_size(&val.data()) > sizeof(uint128_type))
0756 {
0757 *result = ~static_cast<uint128_type>(0);
0758 return;
0759 }
0760 unsigned char buf[sizeof(uint128_type)];
0761 std::size_t len;
0762 detail::check_tommath_result(mp_to_ubin(&val.data(), buf, sizeof(buf), &len));
0763 *result = 0;
0764 for (std::size_t i = 0; i < len; ++i)
0765 {
0766 *result <<= CHAR_BIT;
0767 *result |= buf[i];
0768 }
0769 #else
0770 std::size_t len = mp_unsigned_bin_size(const_cast<mp_int*>(&val.data()));
0771 if (len > sizeof(uint128_type))
0772 {
0773 *result = ~static_cast<uint128_type>(0);
0774 return;
0775 }
0776 unsigned char buf[sizeof(uint128_type)];
0777 detail::check_tommath_result(mp_to_unsigned_bin(const_cast<mp_int*>(&val.data()), buf));
0778 *result = 0;
0779 for (std::size_t i = 0; i < len; ++i)
0780 {
0781 *result <<= CHAR_BIT;
0782 *result |= buf[i];
0783 }
0784 #endif
0785 }
0786 inline void eval_convert_to(int128_type* result, const tommath_int& val)
0787 {
0788 uint128_type r;
0789 eval_convert_to(&r, val);
0790 if (mp_isneg(&val.data()))
0791 *result = -static_cast<int128_type>(r);
0792 else
0793 *result = r;
0794 }
0795 #endif
0796 #if defined(BOOST_HAS_FLOAT128)
0797 inline void eval_convert_to(float128_type* result, const tommath_int& val) noexcept
0798 {
0799 *result = float128_procs::strtoflt128(val.str(0, std::ios_base::scientific).c_str(), nullptr);
0800 }
0801 #endif
0802 inline void eval_convert_to(long double* result, const tommath_int& val) noexcept
0803 {
0804 *result = std::strtold(val.str(0, std::ios_base::scientific).c_str(), nullptr);
0805 }
0806 inline void eval_convert_to(double* result, const tommath_int& val) noexcept
0807 {
0808 *result = std::strtod(val.str(0, std::ios_base::scientific).c_str(), nullptr);
0809 }
0810 inline void eval_convert_to(float* result, const tommath_int& val) noexcept
0811 {
0812 *result = std::strtof(val.str(0, std::ios_base::scientific).c_str(), nullptr);
0813 }
0814
0815
0816 inline void eval_abs(tommath_int& result, const tommath_int& val)
0817 {
0818 detail::check_tommath_result(mp_abs(const_cast< ::mp_int*>(&val.data()), &result.data()));
0819 }
0820 inline void eval_gcd(tommath_int& result, const tommath_int& a, const tommath_int& b)
0821 {
0822 detail::check_tommath_result(mp_gcd(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
0823 }
0824 inline void eval_lcm(tommath_int& result, const tommath_int& a, const tommath_int& b)
0825 {
0826 detail::check_tommath_result(mp_lcm(const_cast< ::mp_int*>(&a.data()), const_cast< ::mp_int*>(&b.data()), const_cast< ::mp_int*>(&result.data())));
0827 }
0828 inline void eval_powm(tommath_int& result, const tommath_int& base, const tommath_int& p, const tommath_int& m)
0829 {
0830 if (eval_get_sign(p) < 0)
0831 {
0832 BOOST_MP_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
0833 }
0834 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()));
0835 }
0836
0837 inline void eval_qr(const tommath_int& x, const tommath_int& y,
0838 tommath_int& q, tommath_int& r)
0839 {
0840 detail::check_tommath_result(mp_div(const_cast< ::mp_int*>(&x.data()), const_cast< ::mp_int*>(&y.data()), &q.data(), &r.data()));
0841 }
0842
0843 inline std::size_t eval_lsb(const tommath_int& val)
0844 {
0845 int c = eval_get_sign(val);
0846 if (c == 0)
0847 {
0848 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
0849 }
0850 if (c < 0)
0851 {
0852 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
0853 }
0854 return mp_cnt_lsb(const_cast< ::mp_int*>(&val.data()));
0855 }
0856
0857 inline std::size_t eval_msb(const tommath_int& val)
0858 {
0859 int c = eval_get_sign(val);
0860 if (c == 0)
0861 {
0862 BOOST_MP_THROW_EXCEPTION(std::domain_error("No bits were set in the operand."));
0863 }
0864 if (c < 0)
0865 {
0866 BOOST_MP_THROW_EXCEPTION(std::domain_error("Testing individual bits in negative values is not supported - results are undefined."));
0867 }
0868 return mp_count_bits(const_cast< ::mp_int*>(&val.data())) - 1;
0869 }
0870
0871 template <class Integer>
0872 inline typename std::enable_if<boost::multiprecision::detail::is_unsigned<Integer>::value, Integer>::type eval_integer_modulus(const tommath_int& x, Integer val)
0873 {
0874 #ifndef MP_DIGIT_BIT
0875 constexpr const mp_digit m = (static_cast<mp_digit>(1) << DIGIT_BIT) - 1;
0876 #else
0877 constexpr const mp_digit m = (static_cast<mp_digit>(1) << MP_DIGIT_BIT) - 1;
0878 #endif
0879 if (val <= m)
0880 {
0881 mp_digit d;
0882 detail::check_tommath_result(mp_mod_d(const_cast< ::mp_int*>(&x.data()), static_cast<mp_digit>(val), &d));
0883 return d;
0884 }
0885 else
0886 {
0887 return default_ops::eval_integer_modulus(x, val);
0888 }
0889 }
0890 template <class Integer>
0891 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)
0892 {
0893 return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
0894 }
0895
0896 inline std::size_t hash_value(const tommath_int& val)
0897 {
0898 std::size_t result = 0;
0899 std::size_t len = val.data().used;
0900 for (std::size_t i = 0; i < len; ++i)
0901 boost::multiprecision::detail::hash_combine(result, val.data().dp[i]);
0902 boost::multiprecision::detail::hash_combine(result, val.data().sign);
0903 return result;
0904 }
0905
0906 }
0907
0908 template <>
0909 struct number_category<tommath_int> : public std::integral_constant<int, number_kind_integer>
0910 {};
0911
0912 }
0913 }
0914
0915 namespace std {
0916
0917 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0918 class numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >
0919 {
0920 using number_type = boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates>;
0921
0922 public:
0923 static constexpr bool is_specialized = true;
0924
0925
0926
0927
0928 static number_type(min)()
0929 {
0930 return number_type();
0931 }
0932 static number_type(max)()
0933 {
0934 return number_type();
0935 }
0936 static number_type lowest() { return (min)(); }
0937 static constexpr int digits = INT_MAX;
0938 static constexpr int digits10 = (INT_MAX / 1000) * 301L;
0939 static constexpr int max_digits10 = digits10 + 3;
0940 static constexpr bool is_signed = true;
0941 static constexpr bool is_integer = true;
0942 static constexpr bool is_exact = true;
0943 static constexpr int radix = 2;
0944 static number_type epsilon() { return number_type(); }
0945 static number_type round_error() { return number_type(); }
0946 static constexpr int min_exponent = 0;
0947 static constexpr int min_exponent10 = 0;
0948 static constexpr int max_exponent = 0;
0949 static constexpr int max_exponent10 = 0;
0950 static constexpr bool has_infinity = false;
0951 static constexpr bool has_quiet_NaN = false;
0952 static constexpr bool has_signaling_NaN = false;
0953 static constexpr float_denorm_style has_denorm = denorm_absent;
0954 static constexpr bool has_denorm_loss = false;
0955 static number_type infinity() { return number_type(); }
0956 static number_type quiet_NaN() { return number_type(); }
0957 static number_type signaling_NaN() { return number_type(); }
0958 static number_type denorm_min() { return number_type(); }
0959 static constexpr bool is_iec559 = false;
0960 static constexpr bool is_bounded = false;
0961 static constexpr bool is_modulo = false;
0962 static constexpr bool traps = false;
0963 static constexpr bool tinyness_before = false;
0964 static constexpr float_round_style round_style = round_toward_zero;
0965 };
0966
0967 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0968 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits;
0969 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0970 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::digits10;
0971 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0972 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_digits10;
0973 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0974 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_signed;
0975 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0976 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_integer;
0977 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0978 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_exact;
0979 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0980 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::radix;
0981 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0982 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent;
0983 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0984 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::min_exponent10;
0985 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0986 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent;
0987 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0988 constexpr int numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::max_exponent10;
0989 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0990 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_infinity;
0991 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0992 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_quiet_NaN;
0993 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0994 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_signaling_NaN;
0995 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0996 constexpr float_denorm_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm;
0997 template <boost::multiprecision::expression_template_option ExpressionTemplates>
0998 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::has_denorm_loss;
0999 template <boost::multiprecision::expression_template_option ExpressionTemplates>
1000 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_iec559;
1001 template <boost::multiprecision::expression_template_option ExpressionTemplates>
1002 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_bounded;
1003 template <boost::multiprecision::expression_template_option ExpressionTemplates>
1004 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::is_modulo;
1005 template <boost::multiprecision::expression_template_option ExpressionTemplates>
1006 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::traps;
1007 template <boost::multiprecision::expression_template_option ExpressionTemplates>
1008 constexpr bool numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::tinyness_before;
1009 template <boost::multiprecision::expression_template_option ExpressionTemplates>
1010 constexpr float_round_style numeric_limits<boost::multiprecision::number<boost::multiprecision::tommath_int, ExpressionTemplates> >::round_style;
1011
1012 }
1013
1014 #endif