File indexing completed on 2025-01-18 09:42:13
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MP_ADD_UNSIGNED_HPP
0008 #define BOOST_MP_ADD_UNSIGNED_HPP
0009
0010 #include <boost/multiprecision/cpp_int/intel_intrinsics.hpp>
0011 #include <boost/multiprecision/detail/assert.hpp>
0012
0013 namespace boost { namespace multiprecision { namespace backends {
0014
0015 template <class CppInt1, class CppInt2, class CppInt3>
0016 inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned_constexpr(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
0017 {
0018 using ::boost::multiprecision::std_constexpr::swap;
0019
0020
0021
0022
0023
0024 double_limb_type carry = 0;
0025 std::size_t m(0), x(0);
0026 std::size_t as = a.size();
0027 std::size_t bs = b.size();
0028 minmax(as, bs, m, x);
0029 if (x == 1)
0030 {
0031 bool s = a.sign();
0032 result = static_cast<double_limb_type>(*a.limbs()) + static_cast<double_limb_type>(*b.limbs());
0033 result.sign(s);
0034 return;
0035 }
0036 result.resize(x, x);
0037 typename CppInt2::const_limb_pointer pa = a.limbs();
0038 typename CppInt3::const_limb_pointer pb = b.limbs();
0039 typename CppInt1::limb_pointer pr = result.limbs();
0040 typename CppInt1::limb_pointer pr_end = pr + m;
0041
0042 if (as < bs)
0043 swap(pa, pb);
0044
0045
0046 while (pr != pr_end)
0047 {
0048 carry += static_cast<double_limb_type>(*pa) + static_cast<double_limb_type>(*pb);
0049 #ifdef __MSVC_RUNTIME_CHECKS
0050 *pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0051 #else
0052 *pr = static_cast<limb_type>(carry);
0053 #endif
0054 carry >>= CppInt1::limb_bits;
0055 ++pr, ++pa, ++pb;
0056 }
0057 pr_end += x - m;
0058
0059 while (pr != pr_end)
0060 {
0061 if (!carry)
0062 {
0063 if (pa != pr)
0064 std_constexpr::copy(pa, pa + (pr_end - pr), pr);
0065 break;
0066 }
0067 carry += static_cast<double_limb_type>(*pa);
0068 #ifdef __MSVC_RUNTIME_CHECKS
0069 *pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
0070 #else
0071 *pr = static_cast<limb_type>(carry);
0072 #endif
0073 carry >>= CppInt1::limb_bits;
0074 ++pr, ++pa;
0075 }
0076 if (carry)
0077 {
0078
0079 result.resize(x + 1, x + 1);
0080 if (result.size() > x)
0081 result.limbs()[x] = static_cast<limb_type>(1u);
0082 }
0083 result.normalize();
0084 result.sign(a.sign());
0085 }
0086
0087
0088
0089 template <class CppInt1, class CppInt2, class CppInt3>
0090 inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned_constexpr(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
0091 {
0092 using ::boost::multiprecision::std_constexpr::swap;
0093
0094
0095
0096
0097
0098 double_limb_type borrow = 0;
0099 std::size_t m(0), x(0);
0100 minmax(a.size(), b.size(), m, x);
0101
0102
0103
0104 if (x == 1)
0105 {
0106 bool s = a.sign();
0107 limb_type al = *a.limbs();
0108 limb_type bl = *b.limbs();
0109 if (bl > al)
0110 {
0111 ::boost::multiprecision::std_constexpr::swap(al, bl);
0112 s = !s;
0113 }
0114 result = al - bl;
0115 result.sign(s);
0116 return;
0117 }
0118
0119
0120 int c = a.compare_unsigned(b);
0121
0122 result.resize(x, x);
0123
0124 typename CppInt2::const_limb_pointer pa = a.limbs();
0125 typename CppInt3::const_limb_pointer pb = b.limbs();
0126 typename CppInt1::limb_pointer pr = result.limbs();
0127 bool swapped = false;
0128 if (c < 0)
0129 {
0130 swap(pa, pb);
0131 swapped = true;
0132 }
0133 else if (c == 0)
0134 {
0135 result = static_cast<limb_type>(0);
0136 return;
0137 }
0138
0139 std::size_t i = 0;
0140
0141 while (i < m)
0142 {
0143 borrow = static_cast<double_limb_type>(pa[i]) - static_cast<double_limb_type>(pb[i]) - borrow;
0144 pr[i] = static_cast<limb_type>(borrow);
0145 borrow = (borrow >> CppInt1::limb_bits) & 1u;
0146 ++i;
0147 }
0148
0149 while (borrow && (i < x))
0150 {
0151 borrow = static_cast<double_limb_type>(pa[i]) - borrow;
0152 pr[i] = static_cast<limb_type>(borrow);
0153 borrow = (borrow >> CppInt1::limb_bits) & 1u;
0154 ++i;
0155 }
0156
0157 if ((x != i) && (pa != pr))
0158 std_constexpr::copy(pa + i, pa + x, pr + i);
0159 BOOST_MP_ASSERT(0 == borrow);
0160
0161
0162
0163
0164 result.normalize();
0165 result.sign(a.sign());
0166 if (swapped)
0167 result.negate();
0168 }
0169
0170
0171 #ifdef BOOST_MP_HAS_IMMINTRIN_H
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188 template <class CppInt1, class CppInt2, class CppInt3>
0189 inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
0190 {
0191 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
0192 if (BOOST_MP_IS_CONST_EVALUATED(a.size()))
0193 {
0194 add_unsigned_constexpr(result, a, b);
0195 }
0196 else
0197 #endif
0198 {
0199 using std::swap;
0200
0201
0202 std::size_t m(0), x(0);
0203 std::size_t as = a.size();
0204 std::size_t bs = b.size();
0205 minmax(as, bs, m, x);
0206 if (x == 1)
0207 {
0208 bool s = a.sign();
0209 result = static_cast<double_limb_type>(*a.limbs()) + static_cast<double_limb_type>(*b.limbs());
0210 result.sign(s);
0211 return;
0212 }
0213 result.resize(x, x);
0214 typename CppInt2::const_limb_pointer pa = a.limbs();
0215 typename CppInt3::const_limb_pointer pb = b.limbs();
0216 typename CppInt1::limb_pointer pr = result.limbs();
0217
0218 if (as < bs)
0219 swap(pa, pb);
0220
0221 std::size_t i = 0;
0222 unsigned char carry = 0;
0223 #if defined(BOOST_MSVC) && !defined(BOOST_HAS_INT128) && defined(_M_X64)
0224
0225
0226
0227
0228 for (; i + 8 <= m; i += 8)
0229 {
0230 carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 0), *(unsigned long long*)(pb + i + 0), (unsigned long long*)(pr + i));
0231 carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 2), *(unsigned long long*)(pb + i + 2), (unsigned long long*)(pr + i + 2));
0232 carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 4), *(unsigned long long*)(pb + i + 4), (unsigned long long*)(pr + i + 4));
0233 carry = _addcarry_u64(carry, *(unsigned long long*)(pa + i + 6), *(unsigned long long*)(pb + i + 6), (unsigned long long*)(pr + i + 6));
0234 }
0235 #else
0236 for (; i + 4 <= m; i += 4)
0237 {
0238 carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 0], pb[i + 0], pr + i);
0239 carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 1], pb[i + 1], pr + i + 1);
0240 carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 2], pb[i + 2], pr + i + 2);
0241 carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i + 3], pb[i + 3], pr + i + 3);
0242 }
0243 #endif
0244 for (; i < m; ++i)
0245 carry = ::boost::multiprecision::detail::addcarry_limb(carry, pa[i], pb[i], pr + i);
0246 for (; i < x && carry; ++i)
0247
0248 carry = ::boost::multiprecision::detail::addcarry_limb(0, pa[i], 1, pr + i);
0249 if (i == x && carry)
0250 {
0251
0252 result.resize(x + 1, x + 1);
0253 if (result.size() > x)
0254 result.limbs()[x] = static_cast<limb_type>(1u);
0255 }
0256 else if ((x != i) && (pa != pr))
0257
0258 std_constexpr::copy(pa + i, pa + x, pr + i);
0259 result.normalize();
0260 result.sign(a.sign());
0261 }
0262 }
0263
0264 template <class CppInt1, class CppInt2, class CppInt3>
0265 inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
0266 {
0267 #ifndef BOOST_MP_NO_CONSTEXPR_DETECTION
0268 if (BOOST_MP_IS_CONST_EVALUATED(a.size()))
0269 {
0270 subtract_unsigned_constexpr(result, a, b);
0271 }
0272 else
0273 #endif
0274 {
0275 using std::swap;
0276
0277
0278 std::size_t m(0), x(0);
0279 minmax(a.size(), b.size(), m, x);
0280
0281
0282
0283 if (x == 1)
0284 {
0285 bool s = a.sign();
0286 limb_type al = *a.limbs();
0287 limb_type bl = *b.limbs();
0288 if (bl > al)
0289 {
0290 ::boost::multiprecision::std_constexpr::swap(al, bl);
0291 s = !s;
0292 }
0293 result = al - bl;
0294 result.sign(s);
0295 return;
0296 }
0297
0298
0299 int c = a.compare_unsigned(b);
0300
0301 result.resize(x, x);
0302
0303 typename CppInt2::const_limb_pointer pa = a.limbs();
0304 typename CppInt3::const_limb_pointer pb = b.limbs();
0305 typename CppInt1::limb_pointer pr = result.limbs();
0306 bool swapped = false;
0307 if (c < 0)
0308 {
0309 swap(pa, pb);
0310 swapped = true;
0311 }
0312 else if (c == 0)
0313 {
0314 result = static_cast<limb_type>(0);
0315 return;
0316 }
0317
0318 std::size_t i = 0;
0319 unsigned char borrow = 0;
0320
0321 #if defined(BOOST_MSVC) && !defined(BOOST_HAS_INT128) && defined(_M_X64)
0322
0323
0324
0325
0326 for (; i + 8 <= m; i += 8)
0327 {
0328 borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i), *reinterpret_cast<const unsigned long long*>(pb + i), reinterpret_cast<unsigned long long*>(pr + i));
0329 borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i + 2), *reinterpret_cast<const unsigned long long*>(pb + i + 2), reinterpret_cast<unsigned long long*>(pr + i + 2));
0330 borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i + 4), *reinterpret_cast<const unsigned long long*>(pb + i + 4), reinterpret_cast<unsigned long long*>(pr + i + 4));
0331 borrow = _subborrow_u64(borrow, *reinterpret_cast<const unsigned long long*>(pa + i + 6), *reinterpret_cast<const unsigned long long*>(pb + i + 6), reinterpret_cast<unsigned long long*>(pr + i + 6));
0332 }
0333 #else
0334 for(; i + 4 <= m; i += 4)
0335 {
0336 borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i], pb[i], pr + i);
0337 borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i + 1], pb[i + 1], pr + i + 1);
0338 borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i + 2], pb[i + 2], pr + i + 2);
0339 borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i + 3], pb[i + 3], pr + i + 3);
0340 }
0341 #endif
0342 for (; i < m; ++i)
0343 borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i], pb[i], pr + i);
0344
0345
0346 while (borrow && (i < x))
0347 {
0348 borrow = boost::multiprecision::detail::subborrow_limb(borrow, pa[i], 0, pr + i);
0349 ++i;
0350 }
0351
0352 if ((x != i) && (pa != pr))
0353 std_constexpr::copy(pa + i, pa + x, pr + i);
0354 BOOST_MP_ASSERT(0 == borrow);
0355
0356
0357
0358
0359 result.normalize();
0360 result.sign(a.sign());
0361 if (swapped)
0362 result.negate();
0363 }
0364 }
0365
0366 #else
0367
0368 template <class CppInt1, class CppInt2, class CppInt3>
0369 inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
0370 {
0371 add_unsigned_constexpr(result, a, b);
0372 }
0373
0374 template <class CppInt1, class CppInt2, class CppInt3>
0375 inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) noexcept(is_non_throwing_cpp_int<CppInt1>::value)
0376 {
0377 subtract_unsigned_constexpr(result, a, b);
0378 }
0379
0380 #endif
0381
0382 } } }
0383
0384
0385 #endif
0386
0387