num_bigint/biguint/
addition.rs1use super::{BigUint, IntDigits};
2
3use crate::big_digit::{self, BigDigit};
4use crate::UsizePromotion;
5
6use core::iter::Sum;
7use core::ops::{Add, AddAssign};
8use num_traits::CheckedAdd;
9
10#[cfg(target_arch = "x86_64")]
11use core::arch::x86_64 as arch;
12
13#[cfg(target_arch = "x86")]
14use core::arch::x86 as arch;
15
16#[cfg(target_arch = "x86_64")]
18cfg_64!(
19 #[inline]
20 #[allow(unused_unsafe)] fn adc(carry: u8, a: u64, b: u64, out: &mut u64) -> u8 {
22 unsafe { arch::_addcarry_u64(carry, a, b, out) }
25 }
26);
27
28#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
29cfg_32!(
30 #[inline]
31 #[allow(unused_unsafe)] fn adc(carry: u8, a: u32, b: u32, out: &mut u32) -> u8 {
33 unsafe { arch::_addcarry_u32(carry, a, b, out) }
36 }
37);
38
39#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
42#[inline]
43fn 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#[inline]
57pub(super) fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
58 debug_assert!(a.len() >= b.len());
59
60 let mut carry = 0;
61 let (a_lo, a_hi) = a.split_at_mut(b.len());
62
63 for (a, b) in a_lo.iter_mut().zip(b) {
64 carry = adc(carry, *a, *b, a);
65 }
66
67 if carry != 0 {
68 for a in a_hi {
69 carry = adc(carry, *a, 0, a);
70 if carry == 0 {
71 break;
72 }
73 }
74 }
75
76 carry as BigDigit
77}
78
79pub(super) fn add2(a: &mut [BigDigit], b: &[BigDigit]) {
85 let carry = __add2(a, b);
86
87 debug_assert!(carry == 0);
88}
89
90forward_all_binop_to_val_ref_commutative!(impl Add for BigUint, add);
91forward_val_assign!(impl AddAssign for BigUint, add_assign);
92
93impl Add<&BigUint> for BigUint {
94 type Output = BigUint;
95
96 fn add(mut self, other: &BigUint) -> BigUint {
97 self += other;
98 self
99 }
100}
101impl AddAssign<&BigUint> for BigUint {
102 #[inline]
103 fn add_assign(&mut self, other: &BigUint) {
104 let self_len = self.data.len();
105 let mut other = &*other.data;
106 if self_len < other.len() {
107 let (low, high) = other.split_at(self_len);
108 self.data.extend_from_slice(high);
109 other = low;
110 }
111 let carry = __add2(&mut self.data, other);
112 if carry != 0 {
113 self.data.push(carry);
114 }
115 }
116}
117
118promote_unsigned_scalars!(impl Add for BigUint, add);
119promote_unsigned_scalars_assign!(impl AddAssign for BigUint, add_assign);
120forward_all_scalar_binop_to_val_val_commutative!(impl Add<u32> for BigUint, add);
121forward_all_scalar_binop_to_val_val_commutative!(impl Add<u64> for BigUint, add);
122forward_all_scalar_binop_to_val_val_commutative!(impl Add<u128> for BigUint, add);
123
124impl Add<u32> for BigUint {
125 type Output = BigUint;
126
127 #[inline]
128 fn add(mut self, other: u32) -> BigUint {
129 self += other;
130 self
131 }
132}
133
134impl AddAssign<u32> for BigUint {
135 #[inline]
136 fn add_assign(&mut self, other: u32) {
137 if other != 0 {
138 if self.data.is_empty() {
139 self.data.push(other as BigDigit);
140 } else {
141 let carry = __add2(&mut self.data, &[other as BigDigit]);
142 if carry != 0 {
143 self.data.push(carry);
144 }
145 }
146 }
147 }
148}
149
150impl Add<u64> for BigUint {
151 type Output = BigUint;
152
153 #[inline]
154 fn add(mut self, other: u64) -> BigUint {
155 self += other;
156 self
157 }
158}
159
160impl 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 fn add_assign(&mut self, other: u64) {
181 if other != 0 {
182 if self.data.is_empty() {
183 self.data.push(other as BigDigit);
184 } else {
185 let carry = __add2(&mut self.data, &[other as BigDigit]);
186 if carry != 0 {
187 self.data.push(carry);
188 }
189 }
190 }
191 }
192 );
193}
194
195impl Add<u128> for BigUint {
196 type Output = BigUint;
197
198 #[inline]
199 fn add(mut self, other: u128) -> BigUint {
200 self += other;
201 self
202 }
203}
204
205impl 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 fn add_assign(&mut self, other: u128) {
234 let (hi, lo) = big_digit::from_doublebigdigit(other);
235 if hi == 0 {
236 *self += lo;
237 } else {
238 while self.data.len() < 2 {
239 self.data.push(0);
240 }
241
242 let carry = __add2(&mut self.data, &[lo, hi]);
243 if carry != 0 {
244 self.data.push(carry);
245 }
246 }
247 }
248 );
249}
250
251impl CheckedAdd for BigUint {
252 #[inline]
253 fn checked_add(&self, v: &BigUint) -> Option<BigUint> {
254 Some(self.add(v))
255 }
256}
257
258impl_sum_iter_type!(BigUint);