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 #include <boost/multiprecision/cpp_int/add_unsigned.hpp>
13 
14 namespace boost { namespace multiprecision { namespace backends {
15 
16 #ifdef _MSC_VER
17 #pragma warning(push)
18 #pragma warning(disable : 4127) // conditional expression is constant
19 #endif
20 
21 //
22 // As above, but for adding a single limb to a non-trivial cpp_int:
23 //
24 template <class CppInt1, class CppInt2>
add_unsigned(CppInt1 & result,const CppInt2 & a,const limb_type & o)25 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)
26 {
27    // Addition using modular arithmetic.
28    // Nothing fancy, just let uintmax_t take the strain:
29    if (&result != &a)
30       result.resize(a.size(), a.size());
31    double_limb_type                     carry = o;
32    typename CppInt1::limb_pointer       pr    = result.limbs();
33    typename CppInt2::const_limb_pointer pa    = a.limbs();
34    unsigned                             i     = 0;
35    // Addition with carry until we either run out of digits or carry is zero:
36    for (; carry && (i < result.size()); ++i)
37    {
38       carry += static_cast<double_limb_type>(pa[i]);
39 #ifdef __MSVC_RUNTIME_CHECKS
40       pr[i] = static_cast<limb_type>(carry & ~static_cast<limb_type>(0));
41 #else
42       pr[i] = static_cast<limb_type>(carry);
43 #endif
44       carry >>= CppInt1::limb_bits;
45    }
46    // Just copy any remaining digits:
47    if (&a != &result)
48    {
49       std_constexpr::copy(pa + i, pa + a.size(), pr + i);
50    }
51    if (carry)
52    {
53       // We overflowed, need to add one more limb:
54       unsigned x = result.size();
55       result.resize(x + 1, x + 1);
56       if (result.size() > x)
57          result.limbs()[x] = static_cast<limb_type>(carry);
58    }
59    result.normalize();
60    result.sign(a.sign());
61 }
62 //
63 // And again to subtract a single limb:
64 //
65 template <class CppInt1, class CppInt2>
subtract_unsigned(CppInt1 & result,const CppInt2 & a,const limb_type & b)66 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)
67 {
68    // Subtract one limb.
69    // Nothing fancy, just let uintmax_t take the strain:
70 #ifdef BOOST_NO_CXX14_CONSTEXPR
71    BOOST_STATIC_CONSTANT(double_limb_type, borrow = static_cast<double_limb_type>(CppInt1::max_limb_value) + 1);
72 #else
73    constexpr double_limb_type borrow = static_cast<double_limb_type>(CppInt1::max_limb_value) + 1;
74 #endif
75    result.resize(a.size(), a.size());
76    typename CppInt1::limb_pointer       pr = result.limbs();
77    typename CppInt2::const_limb_pointer pa = a.limbs();
78    if (*pa >= b)
79    {
80       *pr = *pa - b;
81       if (&result != &a)
82       {
83          std_constexpr::copy(pa + 1, pa + a.size(), pr + 1);
84          result.sign(a.sign());
85       }
86       else if ((result.size() == 1) && (*pr == 0))
87       {
88          result.sign(false); // zero is unsigned.
89       }
90    }
91    else if (result.size() == 1)
92    {
93       *pr = b - *pa;
94       result.sign(!a.sign());
95    }
96    else
97    {
98       *pr        = static_cast<limb_type>((borrow + *pa) - b);
99       unsigned i = 1;
100       while (!pa[i])
101       {
102          pr[i] = CppInt1::max_limb_value;
103          ++i;
104       }
105       pr[i] = pa[i] - 1;
106       if (&result != &a)
107       {
108          ++i;
109          std_constexpr::copy(pa + i, pa + a.size(), pr + i);
110       }
111       result.normalize();
112       result.sign(a.sign());
113    }
114 }
115 
116 //
117 // Now the actual functions called by the front end, all of which forward to one of the above:
118 //
119 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>
120 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)121 eval_add(
122     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
123     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))
124 {
125    eval_add(result, result, o);
126 }
127 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>
128 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)129 eval_add(
130     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
131     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
132     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))
133 {
134    if (a.sign() != b.sign())
135    {
136       subtract_unsigned(result, a, b);
137       return;
138    }
139    add_unsigned(result, a, b);
140 }
141 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
142 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)143 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))
144 {
145    if (result.sign())
146    {
147       subtract_unsigned(result, result, o);
148    }
149    else
150       add_unsigned(result, result, o);
151 }
152 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>
153 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)154 eval_add(
155     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
156     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
157     const limb_type&                                                            o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
158 {
159    if (a.sign())
160    {
161       subtract_unsigned(result, a, o);
162    }
163    else
164       add_unsigned(result, a, o);
165 }
166 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
167 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)168 eval_add(
169     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
170     const signed_limb_type&                                               o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
171 {
172    if (o < 0)
173       eval_subtract(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
174    else if (o > 0)
175       eval_add(result, static_cast<limb_type>(o));
176 }
177 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>
178 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)179 eval_add(
180     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
181     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
182     const signed_limb_type&                                                     o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
183 {
184    if (o < 0)
185       eval_subtract(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
186    else if (o > 0)
187       eval_add(result, a, static_cast<limb_type>(o));
188    else if (&result != &a)
189       result = a;
190 }
191 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
192 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)193 eval_subtract(
194     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
195     const limb_type&                                                      o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
196 {
197    if (result.sign())
198    {
199       add_unsigned(result, result, o);
200    }
201    else
202       subtract_unsigned(result, result, o);
203 }
204 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>
205 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)206 eval_subtract(
207     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
208     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
209     const limb_type&                                                            o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
210 {
211    if (a.sign())
212    {
213       add_unsigned(result, a, o);
214    }
215    else
216    {
217       subtract_unsigned(result, a, o);
218    }
219 }
220 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
221 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)222 eval_subtract(
223     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
224     const signed_limb_type&                                               o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
225 {
226    if (o)
227    {
228       if (o < 0)
229          eval_add(result, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
230       else
231          eval_subtract(result, static_cast<limb_type>(o));
232    }
233 }
234 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>
235 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)236 eval_subtract(
237     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
238     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
239     const signed_limb_type&                                                     o) BOOST_MP_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
240 {
241    if (o)
242    {
243       if (o < 0)
244          eval_add(result, a, static_cast<limb_type>(boost::multiprecision::detail::unsigned_abs(o)));
245       else
246          eval_subtract(result, a, static_cast<limb_type>(o));
247    }
248    else if (&result != &a)
249       result = a;
250 }
251 
252 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
253 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)254 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))
255 {
256 #ifdef BOOST_NO_CXX14_CONSTEXPR
257    static const limb_type one = 1;
258 #else
259    constexpr const limb_type one = 1;
260 #endif
261    if (!result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
262       ++result.limbs()[0];
263    else if (result.sign() && result.limbs()[0])
264    {
265       --result.limbs()[0];
266       if (!result.limbs()[0])
267          result.sign(false);
268    }
269    else
270       eval_add(result, one);
271 }
272 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
273 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)274 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))
275 {
276 #ifdef BOOST_NO_CXX14_CONSTEXPR
277    static const limb_type one = 1;
278 #else
279    constexpr const limb_type one = 1;
280 #endif
281    if (!result.sign() && result.limbs()[0])
282       --result.limbs()[0];
283    else if (result.sign() && (result.limbs()[0] < cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::max_limb_value))
284       ++result.limbs()[0];
285    else
286       eval_subtract(result, one);
287 }
288 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>
289 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)290 eval_subtract(
291     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
292     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))
293 {
294    eval_subtract(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, unsigned MinBits3, unsigned MaxBits3, cpp_integer_type SignType3, cpp_int_check_type Checked3, class Allocator3>
297 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)298 eval_subtract(
299     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
300     const cpp_int_backend<MinBits2, MaxBits2, SignType2, Checked2, Allocator2>& a,
301     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))
302 {
303    if (a.sign() != b.sign())
304    {
305       add_unsigned(result, a, b);
306       return;
307    }
308    subtract_unsigned(result, a, b);
309 }
310 
311 //
312 // Simple addition and subtraction routine for trivial cpp_int's come last:
313 //
314 // One of the arguments is signed:
315 //
316 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
317 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
318     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)319 eval_add(
320     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
321     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))
322 {
323    if (result.sign() != o.sign())
324    {
325       if (*o.limbs() > *result.limbs())
326       {
327          *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
328          result.negate();
329       }
330       else
331          *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
332    }
333    else
334       *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
335    result.normalize();
336 }
337 // Simple version for two unsigned arguments:
338 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
339 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
340     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)341 eval_add(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
342          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))
343 {
344    *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
345    result.normalize();
346 }
347 
348 // signed subtraction:
349 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
350 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
351     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)352 eval_subtract(
353     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
354     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))
355 {
356    if (result.sign() != o.sign())
357    {
358       *result.limbs() = detail::checked_add(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
359    }
360    else if (*result.limbs() < *o.limbs())
361    {
362       *result.limbs() = detail::checked_subtract(*o.limbs(), *result.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
363       result.negate();
364    }
365    else
366       *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
367    result.normalize();
368 }
369 
370 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
371 BOOST_MP_FORCEINLINE BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<
372     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)373 eval_subtract(
374     cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>&       result,
375     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))
376 {
377    *result.limbs() = detail::checked_subtract(*result.limbs(), *o.limbs(), typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
378    result.normalize();
379 }
380 
381 #ifdef _MSC_VER
382 #pragma warning(pop)
383 #endif
384 
385 }}} // namespace boost::multiprecision::backends
386 
387 #endif
388