1 ///////////////////////////////////////////////////////////////
2 // Copyright 2012 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
5 //
6 // Comparison operators for cpp_int_backend:
7 //
8 #ifndef BOOST_MP_CPP_INT_ADD_HPP
9 #define BOOST_MP_CPP_INT_ADD_HPP
10
11 #include <boost/multiprecision/detail/constexpr.hpp>
12
13 namespace boost { namespace multiprecision { namespace backends {
14
15 #ifdef _MSC_VER
16 #pragma warning(push)
17 #pragma warning(disable : 4127) // conditional expression is constant
18 #endif
19
20 //
21 // This is the key addition routine where all the argument types are non-trivial cpp_int's:
22 //
23 template <class CppInt1, class CppInt2, class CppInt3>
add_unsigned(CppInt1 & result,const CppInt2 & a,const CppInt3 & b)24 inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
25 {
26 using ::boost::multiprecision::std_constexpr::swap;
27
28 // Nothing fancy, just let uintmax_t take the strain:
29 double_limb_type carry = 0;
30 unsigned m(0), x(0);
31 unsigned as = a.size();
32 unsigned bs = b.size();
33 minmax(as, bs, m, x);
34 if (x == 1)
35 {
36 bool s = a.sign();
37 result = static_cast<double_limb_type>(*a.limbs()) + static_cast<double_limb_type>(*b.limbs());
38 result.sign(s);
39 return;
40 }
41 result.resize(x, x);
42 typename CppInt2::const_limb_pointer pa = a.limbs();
43 typename CppInt3::const_limb_pointer pb = b.limbs();
44 typename CppInt1::limb_pointer pr = result.limbs();
45 typename CppInt1::limb_pointer pr_end = pr + m;
46
47 if (as < bs)
48 swap(pa, pb);
49
50 // First where a and b overlap:
51 while (pr != pr_end)
52 {
53 carry += static_cast<double_limb_type>(*pa) + static_cast<double_limb_type>(*pb);
54 #ifdef __MSVC_RUNTIME_CHECKS
55 *pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
56 #else
57 *pr = static_cast<limb_type>(carry);
58 #endif
59 carry >>= CppInt1::limb_bits;
60 ++pr, ++pa, ++pb;
61 }
62 pr_end += x - m;
63 // Now where only a has digits:
64 while (pr != pr_end)
65 {
66 if (!carry)
67 {
68 if (pa != pr)
69 std_constexpr::copy(pa, pa + (pr_end - pr), pr);
70 break;
71 }
72 carry += static_cast<double_limb_type>(*pa);
73 #ifdef __MSVC_RUNTIME_CHECKS
74 *pr = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
75 #else
76 *pr = static_cast<limb_type>(carry);
77 #endif
78 carry >>= CppInt1::limb_bits;
79 ++pr, ++pa;
80 }
81 if (carry)
82 {
83 // We overflowed, need to add one more limb:
84 result.resize(x + 1, x + 1);
85 if (result.size() > x)
86 result.limbs()[x] = static_cast<limb_type>(carry);
87 }
88 result.normalize();
89 result.sign(a.sign());
90 }
91 //
92 // As above, but for adding a single limb to a non-trivial cpp_int:
93 //
94 template <class CppInt1, class CppInt2>
add_unsigned(CppInt1 & result,const CppInt2 & a,const limb_type & o)95 inline BOOST_MP_CXX14_CONSTEXPR void add_unsigned(CppInt1& result, const CppInt2& a, const limb_type& o) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
96 {
97 // Addition using modular arithmetic.
98 // Nothing fancy, just let uintmax_t take the strain:
99 if (&result != &a)
100 result.resize(a.size(), a.size());
101 double_limb_type carry = o;
102 typename CppInt1::limb_pointer pr = result.limbs();
103 typename CppInt2::const_limb_pointer pa = a.limbs();
104 unsigned i = 0;
105 // Addition with carry until we either run out of digits or carry is zero:
106 for (; carry && (i < result.size()); ++i)
107 {
108 carry += static_cast<double_limb_type>(pa[i]);
109 #ifdef __MSVC_RUNTIME_CHECKS
110 pr[i] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
111 #else
112 pr[i] = static_cast<limb_type>(carry);
113 #endif
114 carry >>= CppInt1::limb_bits;
115 }
116 // Just copy any remaining digits:
117 if (&a != &result)
118 {
119 for (; i < result.size(); ++i)
120 pr[i] = pa[i];
121 }
122 if (carry)
123 {
124 // We overflowed, need to add one more limb:
125 unsigned x = result.size();
126 result.resize(x + 1, x + 1);
127 if (result.size() > x)
128 result.limbs()[x] = static_cast<limb_type>(carry);
129 }
130 result.normalize();
131 result.sign(a.sign());
132 }
133 //
134 // Core subtraction routine for all non-trivial cpp_int's:
135 //
136 template <class CppInt1, class CppInt2, class CppInt3>
subtract_unsigned(CppInt1 & result,const CppInt2 & a,const CppInt3 & b)137 inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned(CppInt1& result, const CppInt2& a, const CppInt3& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
138 {
139 using ::boost::multiprecision::std_constexpr::swap;
140
141 // Nothing fancy, just let uintmax_t take the strain:
142 double_limb_type borrow = 0;
143 unsigned m(0), x(0);
144 minmax(a.size(), b.size(), m, x);
145 //
146 // special cases for small limb counts:
147 //
148 if (x == 1)
149 {
150 bool s = a.sign();
151 limb_type al = *a.limbs();
152 limb_type bl = *b.limbs();
153 if (bl > al)
154 {
155 ::boost::multiprecision::std_constexpr::swap(al, bl);
156 s = !s;
157 }
158 result = al - bl;
159 result.sign(s);
160 return;
161 }
162 // This isn't used till later, but comparison has to occur before we resize the result,
163 // as that may also resize a or b if this is an inplace operation:
164 int c = a.compare_unsigned(b);
165 // Set up the result vector:
166 result.resize(x, x);
167 // Now that a, b, and result are stable, get pointers to their limbs:
168 typename CppInt2::const_limb_pointer pa = a.limbs();
169 typename CppInt3::const_limb_pointer pb = b.limbs();
170 typename CppInt1::limb_pointer pr = result.limbs();
171 bool swapped = false;
172 if (c < 0)
173 {
174 swap(pa, pb);
175 swapped = true;
176 }
177 else if (c == 0)
178 {
179 result = static_cast<limb_type>(0);
180 return;
181 }
182
183 unsigned i = 0;
184 // First where a and b overlap:
185 while (i < m)
186 {
187 borrow = static_cast<double_limb_type>(pa[i]) - static_cast<double_limb_type>(pb[i]) - borrow;
188 pr[i] = static_cast<limb_type>(borrow);
189 borrow = (borrow >> CppInt1::limb_bits) & 1u;
190 ++i;
191 }
192 // Now where only a has digits, only as long as we've borrowed:
193 while (borrow && (i < x))
194 {
195 borrow = static_cast<double_limb_type>(pa[i]) - borrow;
196 pr[i] = static_cast<limb_type>(borrow);
197 borrow = (borrow >> CppInt1::limb_bits) & 1u;
198 ++i;
199 }
200 // Any remaining digits are the same as those in pa:
201 if ((x != i) && (pa != pr))
202 std_constexpr::copy(pa + i, pa + x, pr + i);
203 BOOST_ASSERT(0 == borrow);
204
205 //
206 // We may have lost digits, if so update limb usage count:
207 //
208 result.normalize();
209 result.sign(a.sign());
210 if (swapped)
211 result.negate();
212 }
213 //
214 // And again to subtract a single limb:
215 //
216 template <class CppInt1, class CppInt2>
subtract_unsigned(CppInt1 & result,const CppInt2 & a,const limb_type & b)217 inline BOOST_MP_CXX14_CONSTEXPR void subtract_unsigned(CppInt1& result, const CppInt2& a, const limb_type& b) BOOST_MP_NOEXCEPT_IF(is_non_throwing_cpp_int<CppInt1>::value)
218 {
219 // Subtract one limb.
220 // Nothing fancy, just let uintmax_t take the strain:
221 #ifdef BOOST_NO_CXX14_CONSTEXPR
222 BOOST_STATIC_CONSTANT(double_limb_type, borrow = static_cast<double_limb_type>(CppInt1::max_limb_value) + 1);
223 #else
224 constexpr double_limb_type borrow = static_cast<double_limb_type>(CppInt1::max_limb_value) + 1;
225 #endif
226 result.resize(a.size(), a.size());
227 typename CppInt1::limb_pointer pr = result.limbs();
228 typename CppInt2::const_limb_pointer pa = a.limbs();
229 if (*pa >= b)
230 {
231 *pr = *pa - b;
232 if (&result != &a)
233 {
234 std_constexpr::copy(pa + 1, pa + a.size(), pr + 1);
235 result.sign(a.sign());
236 }
237 else if ((result.size() == 1) && (*pr == 0))
238 {
239 result.sign(false); // zero is unsigned.
240 }
241 }
242 else if (result.size() == 1)
243 {
244 *pr = b - *pa;
245 result.sign(!a.sign());
246 }
247 else
248 {
249 *pr = static_cast<limb_type>((borrow + *pa) - b);
250 unsigned i = 1;
251 while (!pa[i])
252 {
253 pr[i] = CppInt1::max_limb_value;
254 ++i;
255 }
256 pr[i] = pa[i] - 1;
257 if (&result != &a)
258 {
259 ++i;
260 std_constexpr::copy(pa + i, pa + a.size(), pr + i);
261 }
262 result.normalize();
263 result.sign(a.sign());
264 }
265 }
266
267 //
268 // Now the actual functions called by the front end, all of which forward to one of the above:
269 //
270 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
271 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)272 eval_add(
273 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
274 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
275 {
276 eval_add(result, result, o);
277 }
278 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
279 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & a,const cpp_int_backend<MinBits3,MaxBits3,SignType3,Checked3,Allocator3> & b)280 eval_add(
281 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
282 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
283 const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
284 {
285 if (a.sign() != b.sign())
286 {
287 subtract_unsigned(result, a, b);
288 return;
289 }
290 add_unsigned(result, a, b);
291 }
292 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
293 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const limb_type & o)294 eval_add(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
295 {
296 if (result.sign())
297 {
298 subtract_unsigned(result, result, o);
299 }
300 else
301 add_unsigned(result, result, o);
302 }
303 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
304 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & a,const limb_type & o)305 eval_add(
306 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
307 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
308 const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
309 {
310 if (a.sign())
311 {
312 subtract_unsigned(result, a, o);
313 }
314 else
315 add_unsigned(result, a, o);
316 }
317 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
318 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const signed_limb_type & o)319 eval_add(
320 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
321 const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
322 {
323 if (o < 0)
324 eval_subtract(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
325 else if (o > 0)
326 eval_add(result, static_cast<limb_type>(o));
327 }
328 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
329 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & a,const signed_limb_type & o)330 eval_add(
331 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
332 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
333 const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
334 {
335 if (o < 0)
336 eval_subtract(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
337 else if (o > 0)
338 eval_add(result, a, static_cast<limb_type>(o));
339 else if (&result != &a)
340 result = a;
341 }
342 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
343 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const limb_type & o)344 eval_subtract(
345 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
346 const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
347 {
348 if (result.sign())
349 {
350 add_unsigned(result, result, o);
351 }
352 else
353 subtract_unsigned(result, result, o);
354 }
355 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
356 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & a,const limb_type & o)357 eval_subtract(
358 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
359 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
360 const limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
361 {
362 if (a.sign())
363 {
364 add_unsigned(result, a, o);
365 }
366 else
367 {
368 subtract_unsigned(result, a, o);
369 }
370 }
371 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
372 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const signed_limb_type & o)373 eval_subtract(
374 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
375 const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
376 {
377 if (o)
378 {
379 if (o < 0)
380 eval_add(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
381 else
382 eval_subtract(result, static_cast<limb_type>(o));
383 }
384 }
385 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
386 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & a,const signed_limb_type & o)387 eval_subtract(
388 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
389 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
390 const signed_limb_type& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
391 {
392 if (o)
393 {
394 if (o < 0)
395 eval_add(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
396 else
397 eval_subtract(result, a, static_cast<limb_type>(o));
398 }
399 else if (&result != &a)
400 result = a;
401 }
402
403 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
404 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_increment(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result)405 eval_increment(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
406 {
407 #ifdef BOOST_NO_CXX14_CONSTEXPR
408 static const limb_type one = 1;
409 #else
410 constexpr const limb_type one = 1;
411 #endif
412 if (!result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
413 ++result.limbs()[0];
414 else if (result.sign() && result.limbs()[0])
415 {
416 --result.limbs()[0];
417 if (!result.limbs()[0])
418 result.sign(false);
419 }
420 else
421 eval_add(result, one);
422 }
423 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
424 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
eval_decrement(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result)425 eval_decrement(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
426 {
427 #ifdef BOOST_NO_CXX14_CONSTEXPR
428 static const limb_type one = 1;
429 #else
430 constexpr const limb_type one = 1;
431 #endif
432 if (!result.sign() && result.limbs()[0])
433 --result.limbs()[0];
434 else if (result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
435 ++result.limbs()[0];
436 else
437 eval_subtract(result, one);
438 }
439 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2>
440 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & o)441 eval_subtract(
442 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
443 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
444 {
445 eval_subtract(result, result, o);
446 }
447 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, unsigned MinBits2, unsigned MaxBits2, cpp_integer_type SignType2, cpp_int_check_type Checked2, class Allocator2, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
448 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<!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
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits2,MaxBits2,SignType2,Checked2,Allocator2> & a,const cpp_int_backend<MinBits3,MaxBits3,SignType3,Checked3,Allocator3> & b)449 eval_subtract(
450 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
451 const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
452 const cpp_int_backend<MinBits3, MaxBits3, SignType3, Checked3, Allocator3>& b) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
453 {
454 if (a.sign() != b.sign())
455 {
456 add_unsigned(result, a, b);
457 return;
458 }
459 subtract_unsigned(result, a, b);
460 }
461
462 //
463 // Simple addition and subtraction routine for trivial cpp_int's come last:
464 //
465 // One of the arguments is signed:
466 //
467 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
468 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
469 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
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & o)470 eval_add(
471 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
472 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
473 {
474 if (result.sign() != o.sign())
475 {
476 if (*o.limbs() > *result.limbs())
477 {
478 *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
479 result.negate();
480 }
481 else
482 *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
483 }
484 else
485 *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
486 result.normalize();
487 }
488 // Simple version for two unsigned arguments:
489 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
490 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
491 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
eval_add(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & o)492 eval_add(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
493 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
494 {
495 *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
496 result.normalize();
497 }
498
499 // signed subtraction:
500 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
501 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
502 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
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & o)503 eval_subtract(
504 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
505 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
506 {
507 if (result.sign() != o.sign())
508 {
509 *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
510 }
511 else if (*result.limbs() < *o.limbs())
512 {
513 *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
514 result.negate();
515 }
516 else
517 *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
518 result.normalize();
519 }
520
521 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
522 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
523 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
eval_subtract(cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & result,const cpp_int_backend<MinBits1,MaxBits1,SignType1,Checked1,Allocator1> & o)524 eval_subtract(
525 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
526 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
527 {
528 *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
529 result.normalize();
530 }
531
532 #ifdef _MSC_VER
533 #pragma warning(pop)
534 #endif
535
536 }}} // namespace boost::multiprecision::backends
537
538 #endif
539