Skip to main content

malachite_nz/natural/arithmetic/
checked_sub_mul.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::natural::InnerNatural::{Large, Small};
10use crate::natural::Natural;
11use crate::natural::arithmetic::sub_mul::{
12    limbs_sub_mul, limbs_sub_mul_in_place_left, limbs_sub_mul_limb_greater,
13    limbs_sub_mul_limb_greater_in_place_left,
14};
15use crate::platform::Limb;
16use malachite_base::num::arithmetic::traits::{CheckedSub, CheckedSubMul};
17use malachite_base::num::basic::traits::Zero;
18
19macro_rules! large_left {
20    ($a_limbs: ident, $b_limbs: ident, $c_limbs: ident) => {
21        (
22            Natural(Large($a_limbs)),
23            Natural(Large($b_limbs)),
24            Natural(Large($c_limbs)),
25        )
26    };
27}
28
29macro_rules! large_right {
30    ($self: ident, $a_limbs: ident, $b_limbs: ident, $c_limbs: ident) => {{
31        let borrow = $a_limbs.len() < $b_limbs.len() + $c_limbs.len() - 1
32            || limbs_sub_mul_in_place_left($a_limbs, &$b_limbs, &$c_limbs);
33        if !borrow {
34            $self.trim();
35        }
36        borrow
37    }};
38}
39
40impl Natural {
41    fn checked_sub_mul_limb_ref_ref(&self, b: &Self, c: Limb) -> Option<Self> {
42        match (self, b, c) {
43            (a, _, 0) | (a, &Self::ZERO, _) => Some(a.clone()),
44            (a, b @ Self(Small(_)), c) => a.checked_sub(b * Self::from(c)),
45            (Self(Small(_)), _, _) => None,
46            (Self(Large(a_limbs)), Self(Large(b_limbs)), c) => {
47                if a_limbs.len() >= b_limbs.len() {
48                    limbs_sub_mul_limb_greater(a_limbs, b_limbs, c).map(Self::from_owned_limbs_asc)
49                } else {
50                    None
51                }
52            }
53        }
54    }
55
56    fn sub_mul_assign_limb_no_panic(&mut self, b: Self, c: Limb) -> bool {
57        match (&mut *self, b, c) {
58            (_, _, 0) | (_, Self::ZERO, _) => false,
59            (a, b @ Self(Small(_)), c) => a.sub_assign_no_panic(b * Self::from(c)),
60            (Self(Small(_)), _, _) => true,
61            (Self(Large(a_limbs)), Self(Large(b_limbs)), c) => {
62                let borrow = a_limbs.len() < b_limbs.len()
63                    || limbs_sub_mul_limb_greater_in_place_left(a_limbs, &b_limbs, c) != 0;
64                if !borrow {
65                    self.trim();
66                }
67                borrow
68            }
69        }
70    }
71
72    fn sub_mul_assign_limb_ref_no_panic(&mut self, b: &Self, c: Limb) -> bool {
73        match (&mut *self, b, c) {
74            (_, _, 0) | (_, &Self::ZERO, _) => false,
75            (a, b @ Self(Small(_)), c) => a.sub_assign_no_panic(b * Self::from(c)),
76            (Self(Small(_)), _, _) => true,
77            (Self(Large(a_limbs)), Self(Large(b_limbs)), c) => {
78                let borrow = a_limbs.len() < b_limbs.len()
79                    || limbs_sub_mul_limb_greater_in_place_left(a_limbs, b_limbs, c) != 0;
80                if !borrow {
81                    self.trim();
82                }
83                borrow
84            }
85        }
86    }
87
88    pub(crate) fn sub_mul_assign_no_panic(&mut self, b: Self, c: Self) -> bool {
89        match (&mut *self, b, c) {
90            (a, Self(Small(small_b)), c) => a.sub_mul_assign_limb_no_panic(c, small_b),
91            (a, b, Self(Small(small_c))) => a.sub_mul_assign_limb_no_panic(b, small_c),
92            (Self(Small(_)), _, _) => true,
93            large_left!(a_limbs, b_limbs, c_limbs) => large_right!(self, a_limbs, b_limbs, c_limbs),
94        }
95    }
96
97    pub(crate) fn sub_mul_assign_val_ref_no_panic(&mut self, b: Self, c: &Self) -> bool {
98        match (&mut *self, &b, c) {
99            (a, Self(Small(small_b)), c) => a.sub_mul_assign_limb_ref_no_panic(c, *small_b),
100            (a, _, Self(Small(small_c))) => a.sub_mul_assign_limb_no_panic(b, *small_c),
101            (Self(Small(_)), _, _) => true,
102            large_left!(a_limbs, b_limbs, c_limbs) => large_right!(self, a_limbs, b_limbs, c_limbs),
103        }
104    }
105
106    pub(crate) fn sub_mul_assign_ref_val_no_panic(&mut self, b: &Self, c: Self) -> bool {
107        match (&mut *self, b, &c) {
108            (a, Self(Small(small_b)), _) => a.sub_mul_assign_limb_no_panic(c, *small_b),
109            (a, b, Self(Small(small_c))) => a.sub_mul_assign_limb_ref_no_panic(b, *small_c),
110            (Self(Small(_)), _, _) => true,
111            large_left!(a_limbs, b_limbs, c_limbs) => large_right!(self, a_limbs, b_limbs, c_limbs),
112        }
113    }
114
115    pub(crate) fn sub_mul_assign_ref_ref_no_panic(&mut self, b: &Self, c: &Self) -> bool {
116        match (&mut *self, b, c) {
117            (a, Self(Small(small_b)), c) => a.sub_mul_assign_limb_ref_no_panic(c, *small_b),
118            (a, b, Self(Small(small_c))) => a.sub_mul_assign_limb_ref_no_panic(b, *small_c),
119            (Self(Small(_)), _, _) => true,
120            large_left!(a_limbs, b_limbs, c_limbs) => large_right!(self, a_limbs, b_limbs, c_limbs),
121        }
122    }
123}
124
125impl CheckedSubMul<Self, Self> for Natural {
126    type Output = Self;
127
128    /// Subtracts a [`Natural`] by the product of two other [`Natural`]s, taking all three by value
129    /// and returning `None` if the result is negative.
130    ///
131    /// $$
132    /// f(x, y, z) = \\begin{cases}
133    ///     \operatorname{Some}(x - yz) & \text{if} \\quad x \geq yz, \\\\
134    ///     \operatorname{None} & \text{otherwise}.
135    /// \\end{cases}
136    /// $$
137    ///
138    /// # Worst-case complexity
139    /// $T(n, m) = O(m + n \log n \log\log n)$
140    ///
141    /// $M(n) = O(n \log n)$
142    ///
143    /// where $T$ is time, $M$ is additional memory, $n$ is `max(y.significant_bits(),
144    /// z.significant_bits())`, and $m$ is `self.significant_bits()`.
145    ///
146    /// # Panics
147    /// Panics if `y * z` is greater than `self`.
148    ///
149    /// # Examples
150    /// ```
151    /// use malachite_base::num::arithmetic::traits::{CheckedSubMul, Pow};
152    /// use malachite_base::strings::ToDebugString;
153    /// use malachite_nz::natural::Natural;
154    ///
155    /// assert_eq!(
156    ///     Natural::from(20u32)
157    ///         .checked_sub_mul(Natural::from(3u32), Natural::from(4u32))
158    ///         .to_debug_string(),
159    ///     "Some(8)"
160    /// );
161    /// assert_eq!(
162    ///     Natural::from(10u32)
163    ///         .checked_sub_mul(Natural::from(3u32), Natural::from(4u32))
164    ///         .to_debug_string(),
165    ///     "None"
166    /// );
167    /// assert_eq!(
168    ///     Natural::from(10u32)
169    ///         .pow(12)
170    ///         .checked_sub_mul(Natural::from(0x10000u32), Natural::from(0x10000u32))
171    ///         .to_debug_string(),
172    ///     "Some(995705032704)"
173    /// );
174    /// ```
175    fn checked_sub_mul(mut self, y: Self, z: Self) -> Option<Self> {
176        if self.sub_mul_assign_no_panic(y, z) {
177            None
178        } else {
179            Some(self)
180        }
181    }
182}
183
184impl<'a> CheckedSubMul<Self, &'a Self> for Natural {
185    type Output = Self;
186
187    /// Subtracts a [`Natural`] by the product of two other [`Natural`]s, taking the first two by
188    /// value and the third by reference and returning `None` if the result is negative.
189    ///
190    /// $$
191    /// f(x, y, z) = \\begin{cases}
192    ///     \operatorname{Some}(x - yz) & \text{if} \\quad x \geq yz, \\\\
193    ///     \operatorname{None} & \text{otherwise}.
194    /// \\end{cases}
195    /// $$
196    ///
197    /// # Worst-case complexity
198    /// $T(n, m) = O(m + n \log n \log\log n)$
199    ///
200    /// $M(n) = O(n \log n)$
201    ///
202    /// where $T$ is time, $M$ is additional memory, $n$ is `max(y.significant_bits(),
203    /// z.significant_bits())`, and $m$ is `self.significant_bits()`.
204    ///
205    /// # Panics
206    /// Panics if `y * z` is greater than `self`.
207    ///
208    /// # Examples
209    /// ```
210    /// use malachite_base::num::arithmetic::traits::{CheckedSubMul, Pow};
211    /// use malachite_base::strings::ToDebugString;
212    /// use malachite_nz::natural::Natural;
213    ///
214    /// assert_eq!(
215    ///     Natural::from(20u32)
216    ///         .checked_sub_mul(Natural::from(3u32), &Natural::from(4u32))
217    ///         .to_debug_string(),
218    ///     "Some(8)"
219    /// );
220    /// assert_eq!(
221    ///     Natural::from(10u32)
222    ///         .checked_sub_mul(Natural::from(3u32), &Natural::from(4u32))
223    ///         .to_debug_string(),
224    ///     "None"
225    /// );
226    /// assert_eq!(
227    ///     Natural::from(10u32)
228    ///         .pow(12)
229    ///         .checked_sub_mul(Natural::from(0x10000u32), &Natural::from(0x10000u32))
230    ///         .to_debug_string(),
231    ///     "Some(995705032704)"
232    /// );
233    /// ```
234    fn checked_sub_mul(mut self, y: Self, z: &'a Self) -> Option<Self> {
235        if self.sub_mul_assign_val_ref_no_panic(y, z) {
236            None
237        } else {
238            Some(self)
239        }
240    }
241}
242
243impl<'a> CheckedSubMul<&'a Self, Self> for Natural {
244    type Output = Self;
245
246    /// Subtracts a [`Natural`] by the product of two other [`Natural`]s, taking the first and third
247    /// by value and the second by reference and returning `None` if the result is negative.
248    ///
249    /// $$
250    /// f(x, y, z) = \\begin{cases}
251    ///     \operatorname{Some}(x - yz) & \text{if} \\quad x \geq yz, \\\\
252    ///     \operatorname{None} & \text{otherwise}.
253    /// \\end{cases}
254    /// $$
255    ///
256    /// # Worst-case complexity
257    /// $T(n, m) = O(m + n \log n \log\log n)$
258    ///
259    /// $M(n) = O(n \log n)$
260    ///
261    /// where $T$ is time, $M$ is additional memory, $n$ is `max(y.significant_bits(),
262    /// z.significant_bits())`, and $m$ is `self.significant_bits()`.
263    ///
264    /// # Panics
265    /// Panics if `y * z` is greater than `self`.
266    ///
267    /// # Examples
268    /// ```
269    /// use malachite_base::num::arithmetic::traits::{CheckedSubMul, Pow};
270    /// use malachite_base::strings::ToDebugString;
271    /// use malachite_nz::natural::Natural;
272    ///
273    /// assert_eq!(
274    ///     Natural::from(20u32)
275    ///         .checked_sub_mul(&Natural::from(3u32), Natural::from(4u32))
276    ///         .to_debug_string(),
277    ///     "Some(8)"
278    /// );
279    /// assert_eq!(
280    ///     Natural::from(10u32)
281    ///         .checked_sub_mul(&Natural::from(3u32), Natural::from(4u32))
282    ///         .to_debug_string(),
283    ///     "None"
284    /// );
285    /// assert_eq!(
286    ///     Natural::from(10u32)
287    ///         .pow(12)
288    ///         .checked_sub_mul(&Natural::from(0x10000u32), Natural::from(0x10000u32))
289    ///         .to_debug_string(),
290    ///     "Some(995705032704)"
291    /// );
292    /// ```
293    fn checked_sub_mul(mut self, y: &'a Self, z: Self) -> Option<Self> {
294        if self.sub_mul_assign_ref_val_no_panic(y, z) {
295            None
296        } else {
297            Some(self)
298        }
299    }
300}
301
302impl<'a, 'b> CheckedSubMul<&'a Self, &'b Self> for Natural {
303    type Output = Self;
304
305    /// Subtracts a [`Natural`] by the product of two other [`Natural`]s, taking the first by value
306    /// and the second and third by reference and returning `None` if the result is negative.
307    ///
308    /// $$
309    /// f(x, y, z) = \\begin{cases}
310    ///     \operatorname{Some}(x - yz) & \text{if} \\quad x \geq yz, \\\\
311    ///     \operatorname{None} & \text{otherwise}.
312    /// \\end{cases}
313    /// $$
314    ///
315    /// # Worst-case complexity
316    /// $T(n, m) = O(m + n \log n \log\log n)$
317    ///
318    /// $M(n) = O(n \log n)$
319    ///
320    /// where $T$ is time, $M$ is additional memory, $n$ is `max(y.significant_bits(),
321    /// z.significant_bits())`, and $m$ is `self.significant_bits()`.
322    ///
323    /// # Panics
324    /// Panics if `y * z` is greater than `self`.
325    ///
326    /// # Examples
327    /// ```
328    /// use malachite_base::num::arithmetic::traits::{CheckedSubMul, Pow};
329    /// use malachite_base::strings::ToDebugString;
330    /// use malachite_nz::natural::Natural;
331    ///
332    /// assert_eq!(
333    ///     Natural::from(20u32)
334    ///         .checked_sub_mul(&Natural::from(3u32), &Natural::from(4u32))
335    ///         .to_debug_string(),
336    ///     "Some(8)"
337    /// );
338    /// assert_eq!(
339    ///     Natural::from(10u32)
340    ///         .checked_sub_mul(&Natural::from(3u32), &Natural::from(4u32))
341    ///         .to_debug_string(),
342    ///     "None"
343    /// );
344    /// assert_eq!(
345    ///     Natural::from(10u32)
346    ///         .pow(12)
347    ///         .checked_sub_mul(&Natural::from(0x10000u32), &Natural::from(0x10000u32))
348    ///         .to_debug_string(),
349    ///     "Some(995705032704)"
350    /// );
351    /// ```
352    fn checked_sub_mul(mut self, y: &'a Self, z: &'b Self) -> Option<Self> {
353        if self.sub_mul_assign_ref_ref_no_panic(y, z) {
354            None
355        } else {
356            Some(self)
357        }
358    }
359}
360
361impl CheckedSubMul<&Natural, &Natural> for &Natural {
362    type Output = Natural;
363
364    /// Subtracts a [`Natural`] by the product of two other [`Natural`]s, taking all three by
365    /// reference and returning `None` if the result is negative.
366    ///
367    /// $$
368    /// f(x, y, z) = \\begin{cases}
369    ///     \operatorname{Some}(x - yz) & \text{if} \\quad x \geq yz, \\\\
370    ///     \operatorname{None} & \text{otherwise}.
371    /// \\end{cases}
372    /// $$
373    ///
374    /// # Worst-case complexity
375    /// $T(n, m) = O(m + n \log n \log\log n)$
376    ///
377    /// $M(n, m) = O(m + n \log n)$
378    ///
379    /// where $T$ is time, $M$ is additional memory, $n$ is `max(y.significant_bits(),
380    /// z.significant_bits())`, and $m$ is `self.significant_bits()`.
381    ///
382    /// # Examples
383    /// ```
384    /// use malachite_base::num::arithmetic::traits::{CheckedSubMul, Pow};
385    /// use malachite_base::strings::ToDebugString;
386    /// use malachite_nz::natural::Natural;
387    ///
388    /// assert_eq!(
389    ///     (&Natural::from(20u32))
390    ///         .checked_sub_mul(&Natural::from(3u32), &Natural::from(4u32))
391    ///         .to_debug_string(),
392    ///     "Some(8)"
393    /// );
394    /// assert_eq!(
395    ///     (&Natural::from(10u32))
396    ///         .checked_sub_mul(&Natural::from(3u32), &Natural::from(4u32))
397    ///         .to_debug_string(),
398    ///     "None"
399    /// );
400    /// assert_eq!(
401    ///     (&Natural::from(10u32).pow(12))
402    ///         .checked_sub_mul(&Natural::from(0x10000u32), &Natural::from(0x10000u32))
403    ///         .to_debug_string(),
404    ///     "Some(995705032704)"
405    /// );
406    /// ```
407    fn checked_sub_mul(self, y: &Natural, z: &Natural) -> Option<Natural> {
408        match (self, y, z) {
409            (x, Natural(Small(small_y)), z) => x.checked_sub_mul_limb_ref_ref(z, *small_y),
410            (x, y, Natural(Small(small_z))) => x.checked_sub_mul_limb_ref_ref(y, *small_z),
411            (Natural(Small(_)), _, _) => None,
412            (Natural(Large(x_limbs)), Natural(Large(y_limbs)), Natural(Large(z_limbs))) => {
413                if x_limbs.len() >= y_limbs.len() + z_limbs.len() - 1 {
414                    limbs_sub_mul(x_limbs, y_limbs, z_limbs).map(Natural::from_owned_limbs_asc)
415                } else {
416                    None
417                }
418            }
419        }
420    }
421}