Chris@16: /////////////////////////////////////////////////////////////// Chris@16: // Copyright 2012 John Maddock. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_ Chris@16: // Chris@16: // Comparison operators for cpp_int_backend: Chris@16: // Chris@16: #ifndef BOOST_MP_CPP_INT_ADD_HPP Chris@16: #define BOOST_MP_CPP_INT_ADD_HPP Chris@16: Chris@16: namespace boost{ namespace multiprecision{ namespace backends{ Chris@16: Chris@16: // Chris@16: // This is the key addition routine where all the argument types are non-trivial cpp_int's: Chris@16: // Chris@16: template Chris@16: inline void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_NOEXCEPT_IF(is_non_throwing_cpp_int::value) Chris@16: { Chris@16: using std::swap; Chris@16: Chris@16: // Nothing fancy, just let uintmax_t take the strain: Chris@16: double_limb_type carry = 0; Chris@16: unsigned m, x; Chris@16: unsigned as = a.size(); Chris@16: unsigned bs = b.size(); Chris@16: minmax(as, bs, m, x); Chris@16: if(x == 1) Chris@16: { Chris@16: bool s = a.sign(); Chris@16: result = static_cast(*a.limbs()) + static_cast(*b.limbs()); Chris@16: result.sign(s); Chris@16: return; Chris@16: } Chris@16: result.resize(x, x); Chris@16: typename CppInt2::const_limb_pointer pa = a.limbs(); Chris@16: typename CppInt3::const_limb_pointer pb = b.limbs(); Chris@16: typename CppInt1::limb_pointer pr = result.limbs(); Chris@16: typename CppInt1::limb_pointer pr_end = pr + m; Chris@16: Chris@16: if(as < bs) Chris@16: swap(pa, pb); Chris@16: Chris@16: // First where a and b overlap: Chris@16: while(pr != pr_end) Chris@16: { Chris@16: carry += static_cast(*pa) + static_cast(*pb); Chris@16: *pr = static_cast(carry); Chris@16: carry >>= CppInt1::limb_bits; Chris@16: ++pr, ++pa, ++pb; Chris@16: } Chris@16: pr_end += x - m; Chris@16: // Now where only a has digits: Chris@16: while(pr != pr_end) Chris@16: { Chris@16: if(!carry) Chris@16: { Chris@16: if(pa != pr) Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, >= 1600) Chris@16: std::copy(pa, pa + (pr_end - pr), stdext::checked_array_iterator(pr, result.size())); Chris@16: #else Chris@16: std::copy(pa, pa + (pr_end - pr), pr); Chris@16: #endif Chris@16: break; Chris@16: } Chris@16: carry += static_cast(*pa); Chris@16: *pr = static_cast(carry); Chris@16: carry >>= CppInt1::limb_bits; Chris@16: ++pr, ++pa; Chris@16: } Chris@16: if(carry) Chris@16: { Chris@16: // We overflowed, need to add one more limb: Chris@16: result.resize(x + 1, x + 1); Chris@16: if(CppInt1::variable || (result.size() > x)) Chris@16: result.limbs()[x] = static_cast(carry); Chris@16: } Chris@16: result.normalize(); Chris@16: result.sign(a.sign()); Chris@16: } Chris@16: // Chris@16: // As above, but for adding a single limb to a non-trivial cpp_int: Chris@16: // Chris@16: template Chris@16: inline void add_unsigned(CppInt1& result, const CppInt2& a, const limb_type& o) BOOST_NOEXCEPT_IF(is_non_throwing_cpp_int::value) Chris@16: { Chris@16: // Addition using modular arithmetic. Chris@16: // Nothing fancy, just let uintmax_t take the strain: Chris@16: if(&result != &a) Chris@16: result.resize(a.size(), a.size()); Chris@16: double_limb_type carry = o; Chris@16: typename CppInt1::limb_pointer pr = result.limbs(); Chris@16: typename CppInt2::const_limb_pointer pa = a.limbs(); Chris@16: unsigned i = 0; Chris@16: // Addition with carry until we either run out of digits or carry is zero: Chris@16: for(; carry && (i < result.size()); ++i) Chris@16: { Chris@16: carry += static_cast(pa[i]); Chris@16: pr[i] = static_cast(carry); Chris@16: carry >>= CppInt1::limb_bits; Chris@16: } Chris@16: // Just copy any remaining digits: Chris@16: if(&a != &result) Chris@16: { Chris@16: for(; i < result.size(); ++i) Chris@16: pr[i] = pa[i]; Chris@16: } Chris@16: if(carry) Chris@16: { Chris@16: // We overflowed, need to add one more limb: Chris@16: unsigned x = result.size(); Chris@16: result.resize(x + 1, x + 1); Chris@16: if(CppInt1::variable || (result.size() > x)) Chris@16: result.limbs()[x] = static_cast(carry); Chris@16: } Chris@16: result.normalize(); Chris@16: result.sign(a.sign()); Chris@16: } Chris@16: // Chris@16: // Core subtraction routine for all non-trivial cpp_int's: Chris@16: // Chris@16: template Chris@16: inline void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_NOEXCEPT_IF(is_non_throwing_cpp_int::value) Chris@16: { Chris@16: using std::swap; Chris@16: Chris@16: // Nothing fancy, just let uintmax_t take the strain: Chris@16: double_limb_type borrow = 0; Chris@16: unsigned m, x; Chris@16: minmax(a.size(), b.size(), m, x); Chris@16: // Chris@16: // special cases for small limb counts: Chris@16: // Chris@16: if(x == 1) Chris@16: { Chris@16: bool s = a.sign(); Chris@16: limb_type al = *a.limbs(); Chris@16: limb_type bl = *b.limbs(); Chris@16: if(bl > al) Chris@16: { Chris@16: std::swap(al, bl); Chris@16: s = !s; Chris@16: } Chris@16: result = al - bl; Chris@16: result.sign(s); Chris@16: return; Chris@16: } Chris@16: // This isn't used till later, but comparison has to occur before we resize the result, Chris@16: // as that may also resize a or b if this is an inplace operation: Chris@16: int c = a.compare_unsigned(b); Chris@16: // Set up the result vector: Chris@16: result.resize(x, x); Chris@16: // Now that a, b, and result are stable, get pointers to their limbs: Chris@16: typename CppInt2::const_limb_pointer pa = a.limbs(); Chris@16: typename CppInt3::const_limb_pointer pb = b.limbs(); Chris@16: typename CppInt1::limb_pointer pr = result.limbs(); Chris@16: bool swapped = false; Chris@16: if(c < 0) Chris@16: { Chris@16: swap(pa, pb); Chris@16: swapped = true; Chris@16: } Chris@16: else if(c == 0) Chris@16: { Chris@16: result = static_cast(0); Chris@16: return; Chris@16: } Chris@16: Chris@16: unsigned i = 0; Chris@16: // First where a and b overlap: Chris@16: while(i < m) Chris@16: { Chris@16: borrow = static_cast(pa[i]) - static_cast(pb[i]) - borrow; Chris@16: pr[i] = static_cast(borrow); Chris@16: borrow = (borrow >> CppInt1::limb_bits) & 1u; Chris@16: ++i; Chris@16: } Chris@16: // Now where only a has digits, only as long as we've borrowed: Chris@16: while(borrow && (i < x)) Chris@16: { Chris@16: borrow = static_cast(pa[i]) - borrow; Chris@16: pr[i] = static_cast(borrow); Chris@16: borrow = (borrow >> CppInt1::limb_bits) & 1u; Chris@16: ++i; Chris@16: } Chris@16: // Any remaining digits are the same as those in pa: Chris@16: if((x != i) && (pa != pr)) Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, >= 1600) Chris@16: std::copy(pa + i, pa + x, stdext::checked_array_iterator(pr + i, result.size() - i)); Chris@16: #else Chris@16: std::copy(pa + i, pa + x, pr + i); Chris@16: #endif Chris@16: BOOST_ASSERT(0 == borrow); Chris@16: Chris@16: // Chris@16: // We may have lost digits, if so update limb usage count: Chris@16: // Chris@16: result.normalize(); Chris@16: result.sign(a.sign()); Chris@16: if(swapped) Chris@16: result.negate(); Chris@16: } Chris@16: // Chris@16: // And again to subtract a single limb: Chris@16: // Chris@16: template Chris@16: inline void subtract_unsigned(CppInt1& result, const CppInt2& a, const limb_type& b) BOOST_NOEXCEPT_IF(is_non_throwing_cpp_int::value) Chris@16: { Chris@16: // Subtract one limb. Chris@16: // Nothing fancy, just let uintmax_t take the strain: Chris@16: BOOST_STATIC_CONSTANT(double_limb_type, borrow = static_cast(CppInt1::max_limb_value) + 1); Chris@16: result.resize(a.size(), a.size()); Chris@16: typename CppInt1::limb_pointer pr = result.limbs(); Chris@16: typename CppInt2::const_limb_pointer pa = a.limbs(); Chris@16: if(*pa >= b) Chris@16: { Chris@16: *pr = *pa - b; Chris@16: if(&result != &a) Chris@16: { Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, >= 1600) Chris@16: std::copy(pa + 1, pa + a.size(), stdext::checked_array_iterator(pr + 1, result.size() - 1)); Chris@16: #else Chris@16: std::copy(pa + 1, pa + a.size(), pr + 1); Chris@16: #endif Chris@16: result.sign(a.sign()); Chris@16: } Chris@16: else if((result.size() == 1) && (*pr == 0)) Chris@16: { Chris@16: result.sign(false); // zero is unsigned. Chris@16: } Chris@16: } Chris@16: else if(result.size() == 1) Chris@16: { Chris@16: *pr = b - *pa; Chris@16: result.sign(!a.sign()); Chris@16: } Chris@16: else Chris@16: { Chris@16: *pr = static_cast((borrow + *pa) - b); Chris@16: unsigned i = 1; Chris@16: while(!pa[i]) Chris@16: { Chris@16: pr[i] = CppInt1::max_limb_value; Chris@16: ++i; Chris@16: } Chris@16: pr[i] = pa[i] - 1; Chris@16: if(&result != &a) Chris@16: { Chris@16: ++i; Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, >= 1600) Chris@16: std::copy(pa + i, pa + a.size(), stdext::checked_array_iterator(pr + i, result.size() - i)); Chris@16: #else Chris@16: std::copy(pa + i, pa + a.size(), pr + i); Chris@16: #endif Chris@16: } Chris@16: result.normalize(); Chris@16: result.sign(a.sign()); Chris@16: } Chris@16: } Chris@16: Chris@16: // Chris@16: // Now the actual functions called by the front end, all of which forward to one of the above: Chris@16: // Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_add( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: eval_add(result, result, o); Chris@16: } Chris@16: template Chris@16: inline typename enable_if_c >::value && !is_trivial_cpp_int >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_add( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const cpp_int_backend& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(a.sign() != b.sign()) Chris@16: { Chris@16: subtract_unsigned(result, a, b); Chris@16: return; Chris@16: } Chris@16: add_unsigned(result, a, b); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_add(cpp_int_backend& result, const limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(result.sign()) Chris@16: { Chris@16: subtract_unsigned(result, result, o); Chris@16: } Chris@16: else Chris@16: add_unsigned(result, result, o); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_add( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(a.sign()) Chris@16: { Chris@16: subtract_unsigned(result, a, o); Chris@16: } Chris@16: else Chris@16: add_unsigned(result, a, o); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_add( Chris@16: cpp_int_backend& result, Chris@16: const signed_limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(o < 0) Chris@101: eval_subtract(result, static_cast(boost::multiprecision::detail::unsigned_abs(o))); Chris@16: else if(o > 0) Chris@16: eval_add(result, static_cast(o)); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_add( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const signed_limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(o < 0) Chris@101: eval_subtract(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(o))); Chris@16: else if(o > 0) Chris@16: eval_add(result, a, static_cast(o)); Chris@16: else if(&result != &a) Chris@16: result = a; Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(result.sign()) Chris@16: { Chris@16: add_unsigned(result, result, o); Chris@16: } Chris@16: else Chris@16: subtract_unsigned(result, result, o); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(a.sign()) Chris@16: { Chris@16: add_unsigned(result, a, o); Chris@16: } Chris@16: else Chris@16: { Chris@16: subtract_unsigned(result, a, o); Chris@16: } Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const signed_limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(o) Chris@16: { Chris@16: if(o < 0) Chris@101: eval_add(result, static_cast(boost::multiprecision::detail::unsigned_abs(o))); Chris@16: else Chris@16: eval_subtract(result, static_cast(o)); Chris@16: } Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const signed_limb_type& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(o) Chris@16: { Chris@16: if(o < 0) Chris@101: eval_add(result, a, static_cast(boost::multiprecision::detail::unsigned_abs(o))); Chris@16: else Chris@16: eval_subtract(result, a, static_cast(o)); Chris@16: } Chris@16: else if(&result != &a) Chris@16: result = a; Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_increment(cpp_int_backend& result) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: static const limb_type one = 1; Chris@16: if(!result.sign() && (result.limbs()[0] < cpp_int_backend::max_limb_value)) Chris@16: ++result.limbs()[0]; Chris@16: else if(result.sign() && result.limbs()[0]) Chris@16: --result.limbs()[0]; Chris@16: else Chris@16: eval_add(result, one); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value>::type Chris@16: eval_decrement(cpp_int_backend& result) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: static const limb_type one = 1; Chris@16: if(!result.sign() && result.limbs()[0]) Chris@16: --result.limbs()[0]; Chris@16: else if(result.sign() && (result.limbs()[0] < cpp_int_backend::max_limb_value)) Chris@16: ++result.limbs()[0]; Chris@16: else Chris@16: eval_subtract(result, one); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: eval_subtract(result, result, o); Chris@16: } Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c >::value && !is_trivial_cpp_int >::value && !is_trivial_cpp_int >::value >::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& a, Chris@16: const cpp_int_backend& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(a.sign() != b.sign()) Chris@16: { Chris@16: add_unsigned(result, a, b); Chris@16: return; Chris@16: } Chris@16: subtract_unsigned(result, a, b); Chris@16: } Chris@16: Chris@16: // Chris@16: // Simple addition and subtraction routine for trivial cpp_int's come last: Chris@16: // Chris@16: // One of the arguments is signed: Chris@16: // Chris@16: template Chris@16: inline typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: && (is_signed_number >::value || is_signed_number >::value) Chris@16: >::type Chris@16: eval_add( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(result.sign() != o.sign()) Chris@16: { Chris@16: if(*o.limbs() > *result.limbs()) Chris@16: { Chris@16: *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.negate(); Chris@16: } Chris@16: else Chris@16: *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: } Chris@16: else Chris@16: *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.normalize(); Chris@16: } Chris@16: // Simple version for two unsigned arguments: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: && is_unsigned_number >::value Chris@16: && is_unsigned_number >::value Chris@16: >::type Chris@16: eval_add(cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: // signed subtraction: Chris@16: template Chris@16: inline typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: && (is_signed_number >::value || is_signed_number >::value) Chris@16: >::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: if(result.sign() != o.sign()) Chris@16: { Chris@16: *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: } Chris@16: else if(*result.limbs() < *o.limbs()) Chris@16: { Chris@16: *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.negate(); Chris@16: } Chris@16: else Chris@16: *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: template Chris@16: BOOST_MP_FORCEINLINE typename enable_if_c< Chris@16: is_trivial_cpp_int >::value Chris@16: && is_trivial_cpp_int >::value Chris@16: && is_unsigned_number >::value Chris@16: && is_unsigned_number >::value Chris@16: >::type Chris@16: eval_subtract( Chris@16: cpp_int_backend& result, Chris@16: const cpp_int_backend& o) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int >::value)) Chris@16: { Chris@16: *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend::checked_type()); Chris@16: result.normalize(); Chris@16: } Chris@16: Chris@16: }}} // namespaces Chris@16: Chris@16: #endif