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