/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-bigint-0.5.1/src/biguint/addition.rs
Line | Count | Source |
1 | | use super::{BigUint, IntDigits}; |
2 | | |
3 | | use crate::big_digit::{self, BigDigit}; |
4 | | use crate::UsizePromotion; |
5 | | |
6 | | use core::iter::Sum; |
7 | | use core::ops::{Add, AddAssign}; |
8 | | use num_traits::CheckedAdd; |
9 | | |
10 | | #[cfg(target_arch = "x86_64")] |
11 | | use core::arch::x86_64 as arch; |
12 | | |
13 | | #[cfg(target_arch = "x86")] |
14 | | use core::arch::x86 as arch; |
15 | | |
16 | | // Add with carry: |
17 | | #[cfg(target_arch = "x86_64")] |
18 | | cfg_64!( |
19 | | #[inline] |
20 | | #[allow(unused_unsafe)] // TODO(MSRV 1.93): the intrinsic became safe |
21 | 991k | fn adc(carry: u8, a: u64, b: u64, out: &mut u64) -> u8 { |
22 | | // SAFETY: There are absolutely no safety concerns with calling `_addcarry_u64`. |
23 | | // It's just unsafe for API consistency with other intrinsics. |
24 | 991k | unsafe { arch::_addcarry_u64(carry, a, b, out) } |
25 | 991k | } |
26 | | ); |
27 | | |
28 | | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] |
29 | | cfg_32!( |
30 | | #[inline] |
31 | | #[allow(unused_unsafe)] // TODO(MSRV 1.93): the intrinsic became safe |
32 | | fn adc(carry: u8, a: u32, b: u32, out: &mut u32) -> u8 { |
33 | | // SAFETY: There are absolutely no safety concerns with calling `_addcarry_u32`. |
34 | | // It's just unsafe for API consistency with other intrinsics. |
35 | | unsafe { arch::_addcarry_u32(carry, a, b, out) } |
36 | | } |
37 | | ); |
38 | | |
39 | | // fallback for environments where we don't have an addcarry intrinsic |
40 | | // (copied from the standard library's `carrying_add`) |
41 | | #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] |
42 | | #[inline] |
43 | | fn adc(carry: u8, lhs: BigDigit, rhs: BigDigit, out: &mut BigDigit) -> u8 { |
44 | | let (a, b) = lhs.overflowing_add(rhs); |
45 | | let (c, d) = a.overflowing_add(carry as BigDigit); |
46 | | *out = c; |
47 | | u8::from(b || d) |
48 | | } |
49 | | |
50 | | /// Two argument addition of raw slices, `a += b`, returning the carry. |
51 | | /// |
52 | | /// This is used when the data `Vec` might need to resize to push a non-zero carry, so we perform |
53 | | /// the addition first hoping that it will fit. |
54 | | /// |
55 | | /// The caller _must_ ensure that `a` is at least as long as `b`. |
56 | | #[inline] |
57 | 984k | pub(super) fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit { |
58 | 984k | debug_assert!(a.len() >= b.len()); |
59 | | |
60 | 984k | let mut carry = 0; |
61 | 984k | let (a_lo, a_hi) = a.split_at_mut(b.len()); |
62 | | |
63 | 984k | for (a, b) in a_lo.iter_mut().zip(b) { |
64 | 984k | carry = adc(carry, *a, *b, a); |
65 | 984k | } |
66 | | |
67 | 984k | if carry != 0 { |
68 | 6.59k | for a in a_hi { |
69 | 6.59k | carry = adc(carry, *a, 0, a); |
70 | 6.59k | if carry == 0 { |
71 | 6.32k | break; |
72 | 271 | } |
73 | | } |
74 | 978k | } |
75 | | |
76 | 984k | carry as BigDigit |
77 | 984k | } |
78 | | |
79 | | /// Two argument addition of raw slices: |
80 | | /// a += b |
81 | | /// |
82 | | /// The caller _must_ ensure that a is big enough to store the result - typically this means |
83 | | /// resizing a to max(a.len(), b.len()) + 1, to fit a possible carry. |
84 | 984k | pub(super) fn add2(a: &mut [BigDigit], b: &[BigDigit]) { |
85 | 984k | let carry = __add2(a, b); |
86 | | |
87 | 984k | debug_assert!(carry == 0); |
88 | 984k | } |
89 | | |
90 | | forward_all_binop_to_val_ref_commutative!(impl Add for BigUint, add); |
91 | | forward_val_assign!(impl AddAssign for BigUint, add_assign); |
92 | | |
93 | | impl Add<&BigUint> for BigUint { |
94 | | type Output = BigUint; |
95 | | |
96 | 0 | fn add(mut self, other: &BigUint) -> BigUint { |
97 | 0 | self += other; |
98 | 0 | self |
99 | 0 | } |
100 | | } |
101 | | impl AddAssign<&BigUint> for BigUint { |
102 | | #[inline] |
103 | 0 | fn add_assign(&mut self, other: &BigUint) { |
104 | 0 | let self_len = self.data.len(); |
105 | 0 | let mut other = &*other.data; |
106 | 0 | if self_len < other.len() { |
107 | 0 | let (low, high) = other.split_at(self_len); |
108 | 0 | self.data.extend_from_slice(high); |
109 | 0 | other = low; |
110 | 0 | } |
111 | 0 | let carry = __add2(&mut self.data, other); |
112 | 0 | if carry != 0 { |
113 | 0 | self.data.push(carry); |
114 | 0 | } |
115 | 0 | } |
116 | | } |
117 | | |
118 | | promote_unsigned_scalars!(impl Add for BigUint, add); |
119 | | promote_unsigned_scalars_assign!(impl AddAssign for BigUint, add_assign); |
120 | | forward_all_scalar_binop_to_val_val_commutative!(impl Add<u32> for BigUint, add); |
121 | | forward_all_scalar_binop_to_val_val_commutative!(impl Add<u64> for BigUint, add); |
122 | | forward_all_scalar_binop_to_val_val_commutative!(impl Add<u128> for BigUint, add); |
123 | | |
124 | | impl Add<u32> for BigUint { |
125 | | type Output = BigUint; |
126 | | |
127 | | #[inline] |
128 | 0 | fn add(mut self, other: u32) -> BigUint { |
129 | 0 | self += other; |
130 | 0 | self |
131 | 0 | } |
132 | | } |
133 | | |
134 | | impl AddAssign<u32> for BigUint { |
135 | | #[inline] |
136 | 0 | fn add_assign(&mut self, other: u32) { |
137 | 0 | if other != 0 { |
138 | 0 | if self.data.is_empty() { |
139 | 0 | self.data.push(other as BigDigit); |
140 | 0 | } else { |
141 | 0 | let carry = __add2(&mut self.data, &[other as BigDigit]); |
142 | 0 | if carry != 0 { |
143 | 0 | self.data.push(carry); |
144 | 0 | } |
145 | | } |
146 | 0 | } |
147 | 0 | } |
148 | | } |
149 | | |
150 | | impl Add<u64> for BigUint { |
151 | | type Output = BigUint; |
152 | | |
153 | | #[inline] |
154 | 0 | fn add(mut self, other: u64) -> BigUint { |
155 | 0 | self += other; |
156 | 0 | self |
157 | 0 | } |
158 | | } |
159 | | |
160 | | impl AddAssign<u64> for BigUint { |
161 | | cfg_digit!( |
162 | | #[inline] |
163 | | fn add_assign(&mut self, other: u64) { |
164 | | let (hi, lo) = big_digit::from_doublebigdigit(other); |
165 | | if hi == 0 { |
166 | | *self += lo; |
167 | | } else { |
168 | | while self.data.len() < 2 { |
169 | | self.data.push(0); |
170 | | } |
171 | | |
172 | | let carry = __add2(&mut self.data, &[lo, hi]); |
173 | | if carry != 0 { |
174 | | self.data.push(carry); |
175 | | } |
176 | | } |
177 | | } |
178 | | |
179 | | #[inline] |
180 | 0 | fn add_assign(&mut self, other: u64) { |
181 | 0 | if other != 0 { |
182 | 0 | if self.data.is_empty() { |
183 | 0 | self.data.push(other as BigDigit); |
184 | 0 | } else { |
185 | 0 | let carry = __add2(&mut self.data, &[other as BigDigit]); |
186 | 0 | if carry != 0 { |
187 | 0 | self.data.push(carry); |
188 | 0 | } |
189 | | } |
190 | 0 | } |
191 | 0 | } |
192 | | ); |
193 | | } |
194 | | |
195 | | impl Add<u128> for BigUint { |
196 | | type Output = BigUint; |
197 | | |
198 | | #[inline] |
199 | 0 | fn add(mut self, other: u128) -> BigUint { |
200 | 0 | self += other; |
201 | 0 | self |
202 | 0 | } |
203 | | } |
204 | | |
205 | | impl AddAssign<u128> for BigUint { |
206 | | cfg_digit!( |
207 | | #[inline] |
208 | | fn add_assign(&mut self, other: u128) { |
209 | | if other <= u128::from(u64::MAX) { |
210 | | *self += other as u64 |
211 | | } else { |
212 | | let (a, b, c, d) = super::u32_from_u128(other); |
213 | | let carry = if a > 0 { |
214 | | while self.data.len() < 4 { |
215 | | self.data.push(0); |
216 | | } |
217 | | __add2(&mut self.data, &[d, c, b, a]) |
218 | | } else { |
219 | | debug_assert!(b > 0); |
220 | | while self.data.len() < 3 { |
221 | | self.data.push(0); |
222 | | } |
223 | | __add2(&mut self.data, &[d, c, b]) |
224 | | }; |
225 | | |
226 | | if carry != 0 { |
227 | | self.data.push(carry); |
228 | | } |
229 | | } |
230 | | } |
231 | | |
232 | | #[inline] |
233 | 0 | fn add_assign(&mut self, other: u128) { |
234 | 0 | let (hi, lo) = big_digit::from_doublebigdigit(other); |
235 | 0 | if hi == 0 { |
236 | 0 | *self += lo; |
237 | 0 | } else { |
238 | 0 | while self.data.len() < 2 { |
239 | 0 | self.data.push(0); |
240 | 0 | } |
241 | | |
242 | 0 | let carry = __add2(&mut self.data, &[lo, hi]); |
243 | 0 | if carry != 0 { |
244 | 0 | self.data.push(carry); |
245 | 0 | } |
246 | | } |
247 | 0 | } |
248 | | ); |
249 | | } |
250 | | |
251 | | impl CheckedAdd for BigUint { |
252 | | #[inline] |
253 | 0 | fn checked_add(&self, v: &BigUint) -> Option<BigUint> { |
254 | 0 | Some(self.add(v)) |
255 | 0 | } |
256 | | } |
257 | | |
258 | | impl_sum_iter_type!(BigUint); |