malachite_base/num/arithmetic/saturating_sub_mul.rs
1// Copyright © 2025 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::num::arithmetic::traits::{SaturatingSubMul, SaturatingSubMulAssign, UnsignedAbs};
10use crate::num::basic::signeds::PrimitiveSigned;
11use crate::num::basic::unsigneds::PrimitiveUnsigned;
12use crate::num::conversion::traits::WrappingFrom;
13
14fn saturating_sub_mul_unsigned<T: PrimitiveUnsigned>(x: T, y: T, z: T) -> T {
15 x.saturating_sub(y.saturating_mul(z))
16}
17
18fn saturating_sub_mul_assign_unsigned<T: PrimitiveUnsigned>(x: &mut T, y: T, z: T) {
19 x.saturating_sub_assign(y.saturating_mul(z));
20}
21
22macro_rules! impl_saturating_sub_mul_unsigned {
23 ($t:ident) => {
24 impl SaturatingSubMul<$t> for $t {
25 type Output = $t;
26
27 /// Subtracts a number by the product of two other numbers, saturating at the numeric
28 /// bounds instead of overflowing.
29 ///
30 /// $$
31 /// f(x, y, z) = \\begin{cases}
32 /// x - yz & \text{if} \\quad m \leq x - yz \leq M, \\\\
33 /// M & \text{if} \\quad x - yz > M, \\\\
34 /// m & \text{if} \\quad x - yz < m,
35 /// \\end{cases}
36 /// $$
37 /// where $m$ is `Self::MIN` and $M$ is `Self::MAX`.
38 ///
39 /// # Worst-case complexity
40 /// Constant time and additional memory.
41 ///
42 /// # Examples
43 /// See [here](super::saturating_sub_mul#saturating_sub_mul_assign).
44 #[inline]
45 fn saturating_sub_mul(self, y: $t, z: $t) -> $t {
46 saturating_sub_mul_unsigned(self, y, z)
47 }
48 }
49
50 impl SaturatingSubMulAssign<$t> for $t {
51 /// Subtracts a number by the product of two other numbers in place, saturating at the
52 /// numeric bounds instead of overflowing.
53 ///
54 /// $$
55 /// x \gets \\begin{cases}
56 /// x - yz & \text{if} \\quad m \leq x - yz \leq M, \\\\
57 /// M & \text{if} \\quad x - yz > M, \\\\
58 /// m & \text{if} \\quad x - yz < m,
59 /// \\end{cases}
60 /// $$
61 /// where $m$ is `Self::MIN` and $M$ is `Self::MAX`.
62 ///
63 /// # Worst-case complexity
64 /// Constant time and additional memory.
65 ///
66 /// # Examples
67 /// See [here](super::saturating_sub_mul#saturating_sub_mul_assign).
68 #[inline]
69 fn saturating_sub_mul_assign(&mut self, y: $t, z: $t) {
70 saturating_sub_mul_assign_unsigned(self, y, z);
71 }
72 }
73 };
74}
75apply_to_unsigneds!(impl_saturating_sub_mul_unsigned);
76
77fn saturating_sub_mul_signed<
78 U: PrimitiveUnsigned,
79 S: PrimitiveSigned + UnsignedAbs<Output = U> + WrappingFrom<U>,
80>(
81 x: S,
82 y: S,
83 z: S,
84) -> S {
85 if y == S::ZERO || z == S::ZERO {
86 return x;
87 }
88 let x_sign = x >= S::ZERO;
89 if x_sign == ((y >= S::ZERO) != (z >= S::ZERO)) {
90 x.saturating_sub(y.saturating_mul(z))
91 } else {
92 let x = x.unsigned_abs();
93 let product = if let Some(product) = y.unsigned_abs().checked_mul(z.unsigned_abs()) {
94 product
95 } else {
96 return if x_sign { S::MIN } else { S::MAX };
97 };
98 let result = S::wrapping_from(if x_sign {
99 x.wrapping_sub(product)
100 } else {
101 product.wrapping_sub(x)
102 });
103 if x >= product || (x_sign == (result < S::ZERO)) {
104 result
105 } else if x_sign {
106 S::MIN
107 } else {
108 S::MAX
109 }
110 }
111}
112
113macro_rules! impl_saturating_sub_mul_signed {
114 ($t:ident) => {
115 impl SaturatingSubMul<$t> for $t {
116 type Output = $t;
117
118 /// Subtracts a number by the product of two other numbers, saturating at the numeric
119 /// bounds instead of overflowing.
120 ///
121 /// $$
122 /// f(x, y, z) = \\begin{cases}
123 /// x - yz & \text{if} \\quad m \leq x - yz \leq M, \\\\
124 /// M & \text{if} \\quad x - yz > M, \\\\
125 /// m & \text{if} \\quad x - yz < m,
126 /// \\end{cases}
127 /// $$
128 /// where $m$ is `Self::MIN` and $M$ is `Self::MAX`.
129 ///
130 /// # Worst-case complexity
131 /// Constant time and additional memory.
132 ///
133 /// # Examples
134 /// See [here](super::saturating_sub_mul#saturating_sub_mul).
135 #[inline]
136 fn saturating_sub_mul(self, y: $t, z: $t) -> $t {
137 saturating_sub_mul_signed(self, y, z)
138 }
139 }
140
141 impl SaturatingSubMulAssign<$t> for $t {
142 /// Subtracts a number by the product of two other numbers in place, saturating at the
143 /// numeric bounds instead of overflowing.
144 ///
145 /// $$
146 /// x \gets \\begin{cases}
147 /// x - yz & \text{if} \\quad m \leq x - yz \leq M, \\\\
148 /// M & \text{if} \\quad x - yz > M, \\\\
149 /// m & \text{if} \\quad x - yz < m,
150 /// \\end{cases}
151 /// $$
152 /// where $m$ is `Self::MIN` and $M$ is `Self::MAX`.
153 ///
154 /// # Worst-case complexity
155 /// Constant time and additional memory.
156 ///
157 /// # Examples
158 /// See [here](super::saturating_sub_mul#saturating_sub_mul_assign).
159 #[inline]
160 fn saturating_sub_mul_assign(&mut self, y: $t, z: $t) {
161 *self = self.saturating_sub_mul(y, z);
162 }
163 }
164 };
165}
166apply_to_signeds!(impl_saturating_sub_mul_signed);