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