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