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