Coverage Report

Created: 2026-01-16 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-bigint-0.4.4/src/biguint/subtraction.rs
Line
Count
Source
1
#[cfg(not(u64_digit))]
2
use super::u32_from_u128;
3
use super::BigUint;
4
5
use crate::big_digit::{self, BigDigit};
6
use crate::UsizePromotion;
7
8
use core::cmp::Ordering::{Equal, Greater, Less};
9
use core::ops::{Sub, SubAssign};
10
use num_traits::{CheckedSub, Zero};
11
12
#[cfg(all(use_addcarry, target_arch = "x86_64"))]
13
use core::arch::x86_64 as arch;
14
15
#[cfg(all(use_addcarry, target_arch = "x86"))]
16
use core::arch::x86 as arch;
17
18
// Subtract with borrow:
19
#[cfg(all(use_addcarry, u64_digit))]
20
#[inline]
21
0
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
0
    unsafe { arch::_subborrow_u64(borrow, a, b, out) }
25
0
}
26
27
#[cfg(all(use_addcarry, not(u64_digit)))]
28
#[inline]
29
fn 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]
38
fn 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
48
0
pub(super) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
49
0
    let mut borrow = 0;
50
51
0
    let len = Ord::min(a.len(), b.len());
52
0
    let (a_lo, a_hi) = a.split_at_mut(len);
53
0
    let (b_lo, b_hi) = b.split_at(len);
54
55
0
    for (a, b) in a_lo.iter_mut().zip(b_lo) {
56
0
        borrow = sbb(borrow, *a, *b, a);
57
0
    }
58
59
0
    if borrow != 0 {
60
0
        for a in a_hi {
61
0
            borrow = sbb(borrow, *a, 0, a);
62
0
            if borrow == 0 {
63
0
                break;
64
0
            }
65
        }
66
0
    }
67
68
    // note: we're _required_ to fail on underflow
69
0
    assert!(
70
0
        borrow == 0 && b_hi.iter().all(|x| *x == 0),
71
        "Cannot subtract b from a because b is larger than a."
72
    );
73
0
}
74
75
// Only for the Sub impl. `a` and `b` must have same length.
76
#[inline]
77
0
fn __sub2rev(a: &[BigDigit], b: &mut [BigDigit]) -> u8 {
78
0
    debug_assert!(b.len() == a.len());
79
80
0
    let mut borrow = 0;
81
82
0
    for (ai, bi) in a.iter().zip(b) {
83
0
        borrow = sbb(borrow, *ai, *bi, bi);
84
0
    }
85
86
0
    borrow
87
0
}
88
89
0
fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
90
0
    debug_assert!(b.len() >= a.len());
91
92
0
    let len = Ord::min(a.len(), b.len());
93
0
    let (a_lo, a_hi) = a.split_at(len);
94
0
    let (b_lo, b_hi) = b.split_at_mut(len);
95
96
0
    let borrow = __sub2rev(a_lo, b_lo);
97
98
0
    assert!(a_hi.is_empty());
99
100
    // note: we're _required_ to fail on underflow
101
0
    assert!(
102
0
        borrow == 0 && b_hi.iter().all(|x| *x == 0),
103
        "Cannot subtract b from a because b is larger than a."
104
    );
105
0
}
106
107
forward_val_val_binop!(impl Sub for BigUint, sub);
108
forward_ref_ref_binop!(impl Sub for BigUint, sub);
109
forward_val_assign!(impl SubAssign for BigUint, sub_assign);
110
111
impl Sub<&BigUint> for BigUint {
112
    type Output = BigUint;
113
114
0
    fn sub(mut self, other: &BigUint) -> BigUint {
115
0
        self -= other;
116
0
        self
117
0
    }
118
}
119
impl SubAssign<&BigUint> for BigUint {
120
0
    fn sub_assign(&mut self, other: &BigUint) {
121
0
        sub2(&mut self.data[..], &other.data[..]);
122
0
        self.normalize();
123
0
    }
124
}
125
126
impl Sub<BigUint> for &BigUint {
127
    type Output = BigUint;
128
129
0
    fn sub(self, mut other: BigUint) -> BigUint {
130
0
        let other_len = other.data.len();
131
0
        if other_len < self.data.len() {
132
0
            let lo_borrow = __sub2rev(&self.data[..other_len], &mut other.data);
133
0
            other.data.extend_from_slice(&self.data[other_len..]);
134
0
            if lo_borrow != 0 {
135
0
                sub2(&mut other.data[other_len..], &[1])
136
0
            }
137
0
        } else {
138
0
            sub2rev(&self.data[..], &mut other.data[..]);
139
0
        }
140
0
        other.normalized()
141
0
    }
142
}
143
144
promote_unsigned_scalars!(impl Sub for BigUint, sub);
145
promote_unsigned_scalars_assign!(impl SubAssign for BigUint, sub_assign);
146
forward_all_scalar_binop_to_val_val!(impl Sub<u32> for BigUint, sub);
147
forward_all_scalar_binop_to_val_val!(impl Sub<u64> for BigUint, sub);
148
forward_all_scalar_binop_to_val_val!(impl Sub<u128> for BigUint, sub);
149
150
impl Sub<u32> for BigUint {
151
    type Output = BigUint;
152
153
    #[inline]
154
0
    fn sub(mut self, other: u32) -> BigUint {
155
0
        self -= other;
156
0
        self
157
0
    }
158
}
159
160
impl SubAssign<u32> for BigUint {
161
0
    fn sub_assign(&mut self, other: u32) {
162
0
        sub2(&mut self.data[..], &[other as BigDigit]);
163
0
        self.normalize();
164
0
    }
165
}
166
167
impl 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
0
    fn sub(self, mut other: BigUint) -> BigUint {
184
0
        if other.data.is_empty() {
185
0
            other.data.push(self as BigDigit);
186
0
        } else {
187
0
            sub2rev(&[self as BigDigit], &mut other.data[..]);
188
0
        }
189
0
        other.normalized()
190
0
    }
191
}
192
193
impl Sub<u64> for BigUint {
194
    type Output = BigUint;
195
196
    #[inline]
197
0
    fn sub(mut self, other: u64) -> BigUint {
198
0
        self -= other;
199
0
        self
200
0
    }
201
}
202
203
impl 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
0
    fn sub_assign(&mut self, other: u64) {
215
0
        sub2(&mut self.data[..], &[other as BigDigit]);
216
0
        self.normalize();
217
0
    }
218
}
219
220
impl 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
0
    fn sub(self, mut other: BigUint) -> BigUint {
238
0
        if other.data.is_empty() {
239
0
            other.data.push(self);
240
0
        } else {
241
0
            sub2rev(&[self], &mut other.data[..]);
242
0
        }
243
0
        other.normalized()
244
0
    }
245
}
246
247
impl Sub<u128> for BigUint {
248
    type Output = BigUint;
249
250
    #[inline]
251
0
    fn sub(mut self, other: u128) -> BigUint {
252
0
        self -= other;
253
0
        self
254
0
    }
255
}
256
257
impl 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
0
    fn sub_assign(&mut self, other: u128) {
269
0
        let (hi, lo) = big_digit::from_doublebigdigit(other);
270
0
        sub2(&mut self.data[..], &[lo, hi]);
271
0
        self.normalize();
272
0
    }
273
}
274
275
impl 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
0
    fn sub(self, mut other: BigUint) -> BigUint {
293
0
        while other.data.len() < 2 {
294
0
            other.data.push(0);
295
0
        }
296
297
0
        let (hi, lo) = big_digit::from_doublebigdigit(self);
298
0
        sub2rev(&[lo, hi], &mut other.data[..]);
299
0
        other.normalized()
300
0
    }
301
}
302
303
impl CheckedSub for BigUint {
304
    #[inline]
305
0
    fn checked_sub(&self, v: &BigUint) -> Option<BigUint> {
306
0
        match self.cmp(v) {
307
0
            Less => None,
308
0
            Equal => Some(Zero::zero()),
309
0
            Greater => Some(self.sub(v)),
310
        }
311
0
    }
312
}