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