Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-12 08:20:50

0001 ///////////////////////////////////////////////////////////////
0002 //  Copyright 2012 John Maddock. Distributed under the Boost
0003 //  Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
0005 //
0006 // Comparison operators for cpp_int_backend:
0007 //
0008 #ifndef BOOST_MP_CPP_INT_DIVIDE_HPP
0009 #define BOOST_MP_CPP_INT_DIVIDE_HPP
0010 
0011 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0012 #include <boost/multiprecision/detail/assert.hpp>
0013 
0014 namespace boost { namespace multiprecision { namespace backends {
0015 
0016 template <class CppInt1, class CppInt2, class CppInt3>
0017 BOOST_MP_CXX14_CONSTEXPR void divide_unsigned_helper(
0018     CppInt1*       result,
0019     const CppInt2& x,
0020     const CppInt3& y,
0021     CppInt1&       r)
0022 {
0023    if (((void*)result == (void*)&x) || ((void*)&r == (void*)&x))
0024    {
0025       CppInt2 t(x);
0026       divide_unsigned_helper(result, t, y, r);
0027       return;
0028    }
0029    if (((void*)result == (void*)&y) || ((void*)&r == (void*)&y))
0030    {
0031       CppInt3 t(y);
0032       divide_unsigned_helper(result, x, t, r);
0033       return;
0034    }
0035 
0036    /*
0037     Very simple, fairly braindead long division.
0038     Start by setting the remainder equal to x, and the
0039     result equal to 0.  Then in each loop we calculate our
0040     "best guess" for how many times y divides into r,
0041     add our guess to the result, and subtract guess*y
0042     from the remainder r.  One wrinkle is that the remainder
0043     may go negative, in which case we subtract the current guess
0044     from the result rather than adding.  The value of the guess
0045     is determined by dividing the most-significant-limb of the
0046     current remainder by the most-significant-limb of y.
0047 
0048     Note that there are more efficient algorithms than this
0049     available, in particular see Knuth Vol 2.  However for small
0050     numbers of limbs this generally outperforms the alternatives
0051     and avoids the normalisation step which would require extra storage.
0052     */
0053 
0054    using default_ops::eval_subtract;
0055 
0056    if (result == &r)
0057    {
0058       CppInt1 rem;
0059       divide_unsigned_helper(result, x, y, rem);
0060       r = rem;
0061       return;
0062    }
0063 
0064    //
0065    // Find the most significant words of numerator and denominator.
0066    //
0067    std::size_t y_order = y.size() - 1;
0068 
0069    if (y_order == 0)
0070    {
0071       //
0072       // Only a single non-zero limb in the denominator, in this case
0073       // we can use a specialized divide-by-single-limb routine which is
0074       // much faster.  This also handles division by zero:
0075       //
0076       divide_unsigned_helper(result, x, y.limbs()[y_order], r);
0077       return;
0078    }
0079 
0080    typename CppInt2::const_limb_pointer px = x.limbs();
0081    typename CppInt3::const_limb_pointer py = y.limbs();
0082 
0083    std::size_t r_order = x.size() - 1;
0084    if ((r_order == 0) && (*px == 0))
0085    {
0086       // x is zero, so is the result:
0087       r = x;
0088       if (result)
0089          *result = x;
0090       return;
0091    }
0092 
0093    r = x;
0094    r.sign(false);
0095    if (result)
0096       *result = static_cast<limb_type>(0u);
0097    //
0098    // Check if the remainder is already less than the divisor, if so
0099    // we already have the result.  Note we try and avoid a full compare
0100    // if we can:
0101    //
0102    if (r_order <= y_order)
0103    {
0104       if ((r_order < y_order) || (r.compare_unsigned(y) < 0))
0105       {
0106          return;
0107       }
0108    }
0109 
0110    CppInt1 t;
0111    bool    r_neg = false;
0112 
0113    //
0114    // See if we can short-circuit long division, and use basic arithmetic instead:
0115    //
0116    if (r_order == 0)
0117    {
0118       if (result)
0119       {
0120          *result = px[0] / py[0];
0121       }
0122       r = px[0] % py[0];
0123       return;
0124    }
0125    else if (r_order == 1)
0126    {
0127       double_limb_type a = (static_cast<double_limb_type>(px[1]) << CppInt1::limb_bits) | px[0];
0128       double_limb_type b = y_order ? (static_cast<double_limb_type>(py[1]) << CppInt1::limb_bits) | py[0]
0129                                    : py[0];
0130       if (result)
0131       {
0132          *result = a / b;
0133       }
0134       r = a % b;
0135       return;
0136    }
0137    //
0138    // prepare result:
0139    //
0140    if (result)
0141       result->resize(1 + r_order - y_order, 1 + r_order - y_order);
0142    typename CppInt1::const_limb_pointer prem = r.limbs();
0143    // This is initialised just to keep the compiler from emitting useless warnings later on:
0144    typename CppInt1::limb_pointer pr = typename CppInt1::limb_pointer();
0145    if (result)
0146    {
0147       pr = result->limbs();
0148       for (std::size_t i = 1; i < 1 + r_order - y_order; ++i)
0149          pr[i] = 0;
0150    }
0151    bool first_pass = true;
0152 
0153    do
0154    {
0155       //
0156       // Calculate our best guess for how many times y divides into r:
0157       //
0158       limb_type guess = 1;
0159       if ((prem[r_order] <= py[y_order]) && (r_order > 0))
0160       {
0161          double_limb_type a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
0162          double_limb_type b = py[y_order];
0163          double_limb_type v = a / b;
0164          if (v <= CppInt1::max_limb_value)
0165          {
0166             guess = static_cast<limb_type>(v);
0167             --r_order;
0168          }
0169       }
0170       else if (r_order == 0)
0171       {
0172          guess = prem[0] / py[y_order];
0173       }
0174       else
0175       {
0176          double_limb_type a = (static_cast<double_limb_type>(prem[r_order]) << CppInt1::limb_bits) | prem[r_order - 1];
0177          double_limb_type b = (y_order > 0) ? (static_cast<double_limb_type>(py[y_order]) << CppInt1::limb_bits) | py[y_order - 1] : (static_cast<double_limb_type>(py[y_order]) << CppInt1::limb_bits);
0178          BOOST_MP_ASSERT(b);
0179          double_limb_type v = a / b;
0180          guess              = static_cast<limb_type>(v);
0181       }
0182       BOOST_MP_ASSERT(guess); // If the guess ever gets to zero we go on forever....
0183       //
0184       // Update result:
0185       //
0186       std::size_t shift = r_order - y_order;
0187       if (result)
0188       {
0189          if (r_neg)
0190          {
0191             if (pr[shift] > guess)
0192                pr[shift] -= guess;
0193             else
0194             {
0195                t.resize(shift + 1, shift + 1);
0196                t.limbs()[shift] = guess;
0197                for (std::size_t i = 0; i < shift; ++i)
0198                   t.limbs()[i] = 0;
0199                eval_subtract(*result, t);
0200             }
0201          }
0202          else if (CppInt1::max_limb_value - pr[shift] > guess)
0203             pr[shift] += guess;
0204          else
0205          {
0206             t.resize(shift + 1, shift + 1);
0207             t.limbs()[shift] = guess;
0208             for (std::size_t i = 0; i < shift; ++i)
0209                t.limbs()[i] = 0;
0210             eval_add(*result, t);
0211          }
0212       }
0213       //
0214       // Calculate guess * y, we use a fused mutiply-shift O(N) for this
0215       // rather than a full O(N^2) multiply:
0216       //
0217       double_limb_type carry = 0;
0218       t.resize(y.size() + shift + 1, y.size() + shift);
0219       bool                           truncated_t = (t.size() != y.size() + shift + 1);
0220       typename CppInt1::limb_pointer pt          = t.limbs();
0221       for (std::size_t i = 0; i < shift; ++i)
0222          pt[i] = 0;
0223       for (std::size_t i = 0; i < y.size(); ++i)
0224       {
0225          carry += static_cast<double_limb_type>(py[i]) * static_cast<double_limb_type>(guess);
0226 #ifdef __MSVC_RUNTIME_CHECKS
0227          pt[i + shift] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0228 #else
0229          pt[i + shift]    = static_cast<limb_type>(carry);
0230 #endif
0231          carry >>= CppInt1::limb_bits;
0232       }
0233       if (carry && !truncated_t)
0234       {
0235 #ifdef __MSVC_RUNTIME_CHECKS
0236          pt[t.size() - 1] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0237 #else
0238          pt[t.size() - 1] = static_cast<limb_type>(carry);
0239 #endif
0240       }
0241       else if (!truncated_t)
0242       {
0243          t.resize(t.size() - 1, t.size() - 1);
0244       }
0245       //
0246       // Update r in a way that won't actually produce a negative result
0247       // in case the argument types are unsigned:
0248       //
0249       if (truncated_t && carry)
0250       {
0251          // We need to calculate 2^n + t - r
0252          // where n is the number of bits in this type.
0253          // Simplest way is to get 2^n - r by complementing
0254          // r, then add t to it.  Note that we can't call eval_complement
0255          // in case this is a signed checked type:
0256          for (std::size_t i = 0; i <= r_order; ++i)
0257             r.limbs()[i] = ~prem[i];
0258          r.normalize();
0259          eval_increment(r);
0260          eval_add(r, t);
0261          r_neg = !r_neg;
0262       }
0263       else if (r.compare(t) > 0)
0264       {
0265          eval_subtract(r, t);
0266       }
0267       else
0268       {
0269          r.swap(t);
0270          eval_subtract(r, t);
0271          prem  = r.limbs();
0272          r_neg = !r_neg;
0273       }
0274       //
0275       // First time through we need to strip any leading zero, otherwise
0276       // the termination condition goes belly-up:
0277       //
0278       if (result && first_pass)
0279       {
0280          first_pass = false;
0281          while (pr[result->size() - 1] == 0)
0282             result->resize(result->size() - 1, result->size() - 1);
0283       }
0284       //
0285       // Update r_order:
0286       //
0287       r_order = r.size() - 1;
0288       if (r_order < y_order)
0289          break;
0290    }
0291    // Termination condition is really just a check that r > y, but with a common
0292    // short-circuit case handled first:
0293    while ((r_order > y_order) || (r.compare_unsigned(y) >= 0));
0294 
0295    //
0296    // We now just have to normalise the result:
0297    //
0298    if (r_neg && eval_get_sign(r))
0299    {
0300       // We have one too many in the result:
0301       if (result)
0302          eval_decrement(*result);
0303       if (y.sign())
0304       {
0305          r.negate();
0306          eval_subtract(r, y);
0307       }
0308       else
0309          eval_subtract(r, y, r);
0310    }
0311 
0312    BOOST_MP_ASSERT(r.compare_unsigned(y) < 0); // remainder must be less than the divisor or our code has failed
0313 }
0314 
0315 template <class CppInt1, class CppInt2>
0316 BOOST_MP_CXX14_CONSTEXPR void divide_unsigned_helper(
0317     CppInt1*       result,
0318     const CppInt2& x,
0319     limb_type      y,
0320     CppInt1&       r)
0321 {
0322    if (((void*)result == (void*)&x) || ((void*)&r == (void*)&x))
0323    {
0324       CppInt2 t(x);
0325       divide_unsigned_helper(result, t, y, r);
0326       return;
0327    }
0328 
0329    if (result == &r)
0330    {
0331       CppInt1 rem;
0332       divide_unsigned_helper(result, x, y, rem);
0333       r = rem;
0334       return;
0335    }
0336 
0337    // As above, but simplified for integer divisor:
0338 
0339    using default_ops::eval_subtract;
0340 
0341    if (y == 0)
0342    {
0343       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Integer Division by zero."));
0344    }
0345    //
0346    // Find the most significant word of numerator.
0347    //
0348    std::size_t r_order = x.size() - 1;
0349 
0350    //
0351    // Set remainder and result to their initial values:
0352    //
0353    r = x;
0354    r.sign(false);
0355    typename CppInt1::limb_pointer pr = r.limbs();
0356 
0357    //
0358    // check for x < y, try to do this without actually having to
0359    // do a full comparison:
0360    //
0361    if ((r_order == 0) && (*pr < y))
0362    {
0363       if (result)
0364          *result = static_cast<limb_type>(0u);
0365       return;
0366    }
0367 
0368    //
0369    // See if we can short-circuit long division, and use basic arithmetic instead:
0370    //
0371    if (r_order == 0)
0372    {
0373       if (result)
0374       {
0375          *result = *pr / y;
0376          result->sign(x.sign());
0377       }
0378       *pr %= y;
0379       r.sign(x.sign());
0380       return;
0381    }
0382    else if (r_order == 1)
0383    {
0384       double_limb_type a = (static_cast<double_limb_type>(pr[r_order]) << CppInt1::limb_bits) | pr[0];
0385       if (result)
0386       {
0387          *result = a / y;
0388          result->sign(x.sign());
0389       }
0390       r = a % y;
0391       r.sign(x.sign());
0392       return;
0393    }
0394 
0395    // This is initialised just to keep the compiler from emitting useless warnings later on:
0396    typename CppInt1::limb_pointer pres = typename CppInt1::limb_pointer();
0397    if (result)
0398    {
0399       result->resize(r_order + 1, r_order + 1);
0400       pres = result->limbs();
0401       if (result->size() > r_order)
0402          pres[r_order] = 0; // just in case we don't set the most significant limb below.
0403    }
0404 
0405    do
0406    {
0407       //
0408       // Calculate our best guess for how many times y divides into r:
0409       //
0410       if ((pr[r_order] < y) && r_order)
0411       {
0412          double_limb_type a = (static_cast<double_limb_type>(pr[r_order]) << CppInt1::limb_bits) | pr[r_order - 1];
0413          double_limb_type b = a % y;
0414          r.resize(r.size() - 1, r.size() - 1);
0415          --r_order;
0416          pr[r_order] = static_cast<limb_type>(b);
0417          if (result)
0418             pres[r_order] = static_cast<limb_type>(a / y);
0419          if (r_order && pr[r_order] == 0)
0420          {
0421             --r_order; // No remainder, division was exact.
0422             r.resize(r.size() - 1, r.size() - 1);
0423             if (result)
0424                pres[r_order] = static_cast<limb_type>(0u);
0425          }
0426       }
0427       else
0428       {
0429          if (result)
0430             pres[r_order] = pr[r_order] / y;
0431          pr[r_order] %= y;
0432          if (r_order && pr[r_order] == 0)
0433          {
0434             --r_order; // No remainder, division was exact.
0435             r.resize(r.size() - 1, r.size() - 1);
0436             if (result)
0437                pres[r_order] = static_cast<limb_type>(0u);
0438          }
0439       }
0440    }
0441    // Termination condition is really just a check that r >= y, but with two common
0442    // short-circuit cases handled first:
0443    while (r_order || (pr[r_order] >= y));
0444 
0445    if (result)
0446    {
0447       result->normalize();
0448       result->sign(x.sign());
0449    }
0450    r.normalize();
0451    r.sign(x.sign());
0452 
0453    BOOST_MP_ASSERT(r.compare(y) < 0); // remainder must be less than the divisor or our code has failed
0454 }
0455 
0456 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
0457 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
0458 eval_divide(
0459     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0460     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0461     const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
0462 {
0463    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
0464    bool                                                                 s = a.sign() != b.sign();
0465    divide_unsigned_helper(&result, a, b, r);
0466    result.sign(s);
0467 }
0468 
0469 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0470 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0471 eval_divide(
0472     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0473     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0474     limb_type&                                                                  b)
0475 {
0476    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
0477    bool                                                                 s = a.sign();
0478    divide_unsigned_helper(&result, a, b, r);
0479    result.sign(s);
0480 }
0481 
0482 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0483 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0484 eval_divide(
0485     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0486     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0487     signed_limb_type&                                                           b)
0488 {
0489    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> r;
0490    bool                                                                 s = a.sign() != (b < 0);
0491    divide_unsigned_helper(&result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(b)), r);
0492    result.sign(s);
0493 }
0494 
0495 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0496 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0497 eval_divide(
0498     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0499     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b)
0500 {
0501    // There is no in place divide:
0502    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
0503    eval_divide(result, a, b);
0504 }
0505 
0506 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0507 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0508 eval_divide(
0509     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0510     limb_type                                                             b)
0511 {
0512    // There is no in place divide:
0513    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
0514    eval_divide(result, a, b);
0515 }
0516 
0517 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0518 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0519 eval_divide(
0520     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0521     signed_limb_type                                                      b)
0522 {
0523    // There is no in place divide:
0524    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
0525    eval_divide(result, a, b);
0526 }
0527 
0528 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, std::size_t MinBits3, std::size_t MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
0529 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3> >::value>::type
0530 eval_modulus(
0531     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0532     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0533     const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b)
0534 {
0535    bool s = a.sign();
0536    if (b.size() == 1)
0537       eval_modulus(result, a, *b.limbs());
0538    else
0539    {
0540       using cpp_int_backend1_type = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>;
0541 
0542       divide_unsigned_helper(static_cast<cpp_int_backend1_type*>(nullptr), a, b, result);
0543    }
0544    result.sign(s);
0545 }
0546 
0547 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0548 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0549 eval_modulus(
0550     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0551     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0552     const limb_type                                                             mod)
0553 {
0554 
0555    if(mod == 0)
0556      BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0557 
0558    const std::ptrdiff_t n = static_cast<std::ptrdiff_t>(a.size());
0559 
0560    const double_limb_type two_n_mod =
0561       static_cast<double_limb_type>
0562       (
0563          static_cast<double_limb_type>(1u) + static_cast<limb_type>(static_cast<limb_type>(~static_cast<limb_type>(0u) - mod) % mod)
0564       );
0565 
0566    limb_type res = a.limbs()[n - 1] % mod;
0567 
0568    for (std::ptrdiff_t i = n - 2; i >= 0; --i)
0569       res = static_cast<limb_type>(static_cast<double_limb_type>(static_cast<double_limb_type>(res * two_n_mod) + a.limbs()[i]) % mod);
0570    //
0571    // We must not modify result until here in case
0572    // result and a are the same object:
0573    //
0574    result.resize(1, 1);
0575    *result.limbs() = res;
0576    result.sign(a.sign());
0577 }
0578 
0579 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0580 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0581 eval_modulus(
0582    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0583    const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
0584    signed_limb_type                                                            b)
0585 {
0586    const limb_type t = b < 0 ? static_cast<limb_type>(-b) : static_cast<limb_type>(b);
0587    eval_modulus(result, a, t);
0588    result.sign(a.sign());
0589 }
0590 
0591 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, std::size_t MinBits2, std::size_t MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
0592 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && !is_trivial_cpp_int<cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2> >::value>::type
0593 eval_modulus(
0594     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0595     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& b)
0596 {
0597    // There is no in place divide:
0598    cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> a(result);
0599    eval_modulus(result, a, b);
0600 }
0601 
0602 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0603 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0604 eval_modulus(
0605     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0606     limb_type                                                             b)
0607 {
0608    // Single limb modulus is in place:
0609    eval_modulus(result, result, b);
0610 }
0611 
0612 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0613 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0614 eval_modulus(
0615     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0616     signed_limb_type                                                      b)
0617 {
0618    // Single limb modulus is in place:
0619    eval_modulus(result, result, b);
0620 }
0621 
0622 //
0623 // Over again for trivial cpp_int's:
0624 //
0625 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0626 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0627     is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value || is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value)>::type
0628 eval_divide(
0629     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0630     const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
0631 {
0632    if (!*o.limbs())
0633       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0634    *result.limbs() /= *o.limbs();
0635    result.sign(result.sign() != o.sign());
0636 }
0637 
0638 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0639 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0640     is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0641 eval_divide(
0642     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0643     const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
0644 {
0645    if (!*o.limbs())
0646       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0647    *result.limbs() /= *o.limbs();
0648 }
0649 
0650 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
0651 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0652     is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
0653 eval_modulus(
0654     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
0655     const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o)
0656 {
0657    if (!*o.limbs())
0658       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0659    *result.limbs() %= *o.limbs();
0660    result.sign(result.sign());
0661 }
0662 
0663 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class V>
0664 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0665     is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && std::is_unsigned<V>::value>::type
0666 eval_modulus(
0667     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0668     const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0669     V o)
0670 {
0671    using local_limb_type = typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type;
0672 
0673    BOOST_IF_CONSTEXPR(std::numeric_limits<V>::digits > MaxBits1)
0674    {
0675       if (o >= (static_cast<V>(1u) << MaxBits1))
0676       {
0677          // Modulus is larger than any value that the result can hold,
0678          // so the result is just "a":
0679          result = a;
0680          return;
0681       }
0682    }
0683    if (!o)
0684       BOOST_MP_THROW_EXCEPTION(std::overflow_error("Division by zero."));
0685    *result.limbs() = *a.limbs() % static_cast<local_limb_type>(o);
0686    result.sign(a.sign());
0687 }
0688 
0689 template <std::size_t MinBits1, std::size_t MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class V>
0690 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<
0691     is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && std::is_signed<V>::value>::type
0692 eval_modulus(
0693     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
0694     const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
0695     V o)
0696 {
0697    using unsigned_type = typename std::make_unsigned<V>::type;
0698    eval_modulus(result, a, static_cast<unsigned_type>(o < 0 ? -o : o));
0699 }
0700 
0701 }}} // namespace boost::multiprecision::backends
0702 
0703 #endif