Skip to main content

num_bigint/biguint/
subtraction.rs

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