num_bigint/biguint/
subtraction.rs

1#[cfg(not(u64_digit))]
2use super::u32_from_u128;
3use super::BigUint;
4
5use crate::big_digit::{self, BigDigit};
6use crate::UsizePromotion;
7
8use core::cmp::Ordering::{Equal, Greater, Less};
9use core::ops::{Sub, SubAssign};
10use num_traits::{CheckedSub, Zero};
11
12#[cfg(all(use_addcarry, target_arch = "x86_64"))]
13use core::arch::x86_64 as arch;
14
15#[cfg(all(use_addcarry, target_arch = "x86"))]
16use core::arch::x86 as arch;
17
18// Subtract with borrow:
19#[cfg(all(use_addcarry, u64_digit))]
20#[inline]
21fn sbb(borrow: u8, a: u64, b: u64, out: &mut u64) -> u8 {
22    // Safety: There are absolutely no safety concerns with calling `_subborrow_u64`.
23    // It's just unsafe for API consistency with other intrinsics.
24    unsafe { arch::_subborrow_u64(borrow, a, b, out) }
25}
26
27#[cfg(all(use_addcarry, not(u64_digit)))]
28#[inline]
29fn sbb(borrow: u8, a: u32, b: u32, out: &mut u32) -> u8 {
30    // Safety: There are absolutely no safety concerns with calling `_subborrow_u32`.
31    // It's just unsafe for API consistency with other intrinsics.
32    unsafe { arch::_subborrow_u32(borrow, a, b, out) }
33}
34
35// fallback for environments where we don't have a subborrow intrinsic
36#[cfg(not(use_addcarry))]
37#[inline]
38fn sbb(borrow: u8, a: BigDigit, b: BigDigit, out: &mut BigDigit) -> u8 {
39    use crate::big_digit::SignedDoubleBigDigit;
40
41    let difference = SignedDoubleBigDigit::from(a)
42        - SignedDoubleBigDigit::from(b)
43        - SignedDoubleBigDigit::from(borrow);
44    *out = difference as BigDigit;
45    u8::from(difference < 0)
46}
47
48pub(super) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
49    let mut borrow = 0;
50
51    let len = Ord::min(a.len(), b.len());
52    let (a_lo, a_hi) = a.split_at_mut(len);
53    let (b_lo, b_hi) = b.split_at(len);
54
55    for (a, b) in a_lo.iter_mut().zip(b_lo) {
56        borrow = sbb(borrow, *a, *b, a);
57    }
58
59    if borrow != 0 {
60        for a in a_hi {
61            borrow = sbb(borrow, *a, 0, a);
62            if borrow == 0 {
63                break;
64            }
65        }
66    }
67
68    // note: we're _required_ to fail on underflow
69    assert!(
70        borrow == 0 && b_hi.iter().all(|x| *x == 0),
71        "Cannot subtract b from a because b is larger than a."
72    );
73}
74
75// Only for the Sub impl. `a` and `b` must have same length.
76#[inline]
77fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> u8 {
78    debug_assert!(b.len() == a.len());
79
80    let mut borrow = 0;
81
82    for (ai, bi) in a.iter().zip(b) {
83        borrow = sbb(borrow, *ai, *bi, bi);
84    }
85
86    borrow
87}
88
89fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
90    debug_assert!(b.len() >= a.len());
91
92    let len = Ord::min(a.len(), b.len());
93    let (a_lo, a_hi) = a.split_at(len);
94    let (b_lo, b_hi) = b.split_at_mut(len);
95
96    let borrow = __sub2rev(a_lo, b_lo);
97
98    assert!(a_hi.is_empty());
99
100    // note: we're _required_ to fail on underflow
101    assert!(
102        borrow == 0 && b_hi.iter().all(|x| *x == 0),
103        "Cannot subtract b from a because b is larger than a."
104    );
105}
106
107forward_val_val_binop!(impl Sub for BigUint, sub);
108forward_ref_ref_binop!(impl Sub for BigUint, sub);
109forward_val_assign!(impl SubAssign for BigUint, sub_assign);
110
111impl<'a> Sub<&'a BigUint> for BigUint {
112    type Output = BigUint;
113
114    fn sub(mut self, other: &BigUint) -> BigUint {
115        self -= other;
116        self
117    }
118}
119impl<'a> SubAssign<&'a BigUint> for BigUint {
120    fn sub_assign(&mut self, other: &'a BigUint) {
121        sub2(&mut self.data[..], &other.data[..]);
122        self.normalize();
123    }
124}
125
126impl<'a> Sub<BigUint> for &'a BigUint {
127    type Output = BigUint;
128
129    fn sub(self, mut other: BigUint) -> BigUint {
130        let other_len = other.data.len();
131        if other_len < self.data.len() {
132            let lo_borrow = __sub2rev(&self.data[..other_len], &mut other.data);
133            other.data.extend_from_slice(&self.data[other_len..]);
134            if lo_borrow != 0 {
135                sub2(&mut other.data[other_len..], &[1])
136            }
137        } else {
138            sub2rev(&self.data[..], &mut other.data[..]);
139        }
140        other.normalized()
141    }
142}
143
144promote_unsigned_scalars!(impl Sub for BigUint, sub);
145promote_unsigned_scalars_assign!(impl SubAssign for BigUint, sub_assign);
146forward_all_scalar_binop_to_val_val!(impl Sub<u32> for BigUint, sub);
147forward_all_scalar_binop_to_val_val!(impl Sub<u64> for BigUint, sub);
148forward_all_scalar_binop_to_val_val!(impl Sub<u128> for BigUint, sub);
149
150impl Sub<u32> for BigUint {
151    type Output = BigUint;
152
153    #[inline]
154    fn sub(mut self, other: u32) -> BigUint {
155        self -= other;
156        self
157    }
158}
159
160impl SubAssign<u32> for BigUint {
161    fn sub_assign(&mut self, other: u32) {
162        sub2(&mut self.data[..], &[other as BigDigit]);
163        self.normalize();
164    }
165}
166
167impl Sub<BigUint> for u32 {
168    type Output = BigUint;
169
170    #[cfg(not(u64_digit))]
171    #[inline]
172    fn sub(self, mut other: BigUint) -> BigUint {
173        if other.data.len() == 0 {
174            other.data.push(self);
175        } else {
176            sub2rev(&[self], &mut other.data[..]);
177        }
178        other.normalized()
179    }
180
181    #[cfg(u64_digit)]
182    #[inline]
183    fn sub(self, mut other: BigUint) -> BigUint {
184        if other.data.is_empty() {
185            other.data.push(self as BigDigit);
186        } else {
187            sub2rev(&[self as BigDigit], &mut other.data[..]);
188        }
189        other.normalized()
190    }
191}
192
193impl Sub<u64> for BigUint {
194    type Output = BigUint;
195
196    #[inline]
197    fn sub(mut self, other: u64) -> BigUint {
198        self -= other;
199        self
200    }
201}
202
203impl SubAssign<u64> for BigUint {
204    #[cfg(not(u64_digit))]
205    #[inline]
206    fn sub_assign(&mut self, other: u64) {
207        let (hi, lo) = big_digit::from_doublebigdigit(other);
208        sub2(&mut self.data[..], &[lo, hi]);
209        self.normalize();
210    }
211
212    #[cfg(u64_digit)]
213    #[inline]
214    fn sub_assign(&mut self, other: u64) {
215        sub2(&mut self.data[..], &[other as BigDigit]);
216        self.normalize();
217    }
218}
219
220impl Sub<BigUint> for u64 {
221    type Output = BigUint;
222
223    #[cfg(not(u64_digit))]
224    #[inline]
225    fn sub(self, mut other: BigUint) -> BigUint {
226        while other.data.len() < 2 {
227            other.data.push(0);
228        }
229
230        let (hi, lo) = big_digit::from_doublebigdigit(self);
231        sub2rev(&[lo, hi], &mut other.data[..]);
232        other.normalized()
233    }
234
235    #[cfg(u64_digit)]
236    #[inline]
237    fn sub(self, mut other: BigUint) -> BigUint {
238        if other.data.is_empty() {
239            other.data.push(self);
240        } else {
241            sub2rev(&[self], &mut other.data[..]);
242        }
243        other.normalized()
244    }
245}
246
247impl Sub<u128> for BigUint {
248    type Output = BigUint;
249
250    #[inline]
251    fn sub(mut self, other: u128) -> BigUint {
252        self -= other;
253        self
254    }
255}
256
257impl SubAssign<u128> for BigUint {
258    #[cfg(not(u64_digit))]
259    #[inline]
260    fn sub_assign(&mut self, other: u128) {
261        let (a, b, c, d) = u32_from_u128(other);
262        sub2(&mut self.data[..], &[d, c, b, a]);
263        self.normalize();
264    }
265
266    #[cfg(u64_digit)]
267    #[inline]
268    fn sub_assign(&mut self, other: u128) {
269        let (hi, lo) = big_digit::from_doublebigdigit(other);
270        sub2(&mut self.data[..], &[lo, hi]);
271        self.normalize();
272    }
273}
274
275impl Sub<BigUint> for u128 {
276    type Output = BigUint;
277
278    #[cfg(not(u64_digit))]
279    #[inline]
280    fn sub(self, mut other: BigUint) -> BigUint {
281        while other.data.len() < 4 {
282            other.data.push(0);
283        }
284
285        let (a, b, c, d) = u32_from_u128(self);
286        sub2rev(&[d, c, b, a], &mut other.data[..]);
287        other.normalized()
288    }
289
290    #[cfg(u64_digit)]
291    #[inline]
292    fn sub(self, mut other: BigUint) -> BigUint {
293        while other.data.len() < 2 {
294            other.data.push(0);
295        }
296
297        let (hi, lo) = big_digit::from_doublebigdigit(self);
298        sub2rev(&[lo, hi], &mut other.data[..]);
299        other.normalized()
300    }
301}
302
303impl CheckedSub for BigUint {
304    #[inline]
305    fn checked_sub(&self, v: &BigUint) -> Option<BigUint> {
306        match self.cmp(v) {
307            Less => None,
308            Equal => Some(Zero::zero()),
309            Greater => Some(self.sub(v)),
310        }
311    }
312}