Skip to main content

dashu_int/
add_ops.rs

1//! Addition and subtraction operators.
2
3use crate::{helper_macros, ibig::IBig, ubig::UBig, Sign::*};
4use core::ops::{Add, AddAssign, Sub, SubAssign};
5
6helper_macros::forward_ubig_binop_to_repr!(impl Add, add);
7helper_macros::forward_ubig_binop_to_repr!(impl Sub, sub);
8helper_macros::impl_binop_assign_by_taking!(impl AddAssign<UBig> for UBig, add_assign, add);
9helper_macros::impl_binop_assign_by_taking!(impl SubAssign<UBig> for UBig, sub_assign, sub);
10
11macro_rules! impl_ibig_add {
12    ($sign0:ident, $mag0:ident, $sign1:ident, $mag1:ident) => {
13        match ($sign0, $sign1) {
14            (Positive, Positive) => IBig($mag0.add($mag1)),
15            (Positive, Negative) => IBig($mag0.sub_signed($mag1)),
16            (Negative, Positive) => IBig($mag1.sub_signed($mag0)),
17            (Negative, Negative) => IBig($mag0.add($mag1).with_sign(Negative)),
18        }
19    };
20}
21macro_rules! impl_ibig_sub {
22    ($sign0:ident, $mag0:ident, $sign1:ident, $mag1:ident) => {
23        match ($sign0, $sign1) {
24            (Positive, Positive) => IBig($mag0.sub_signed($mag1)),
25            (Positive, Negative) => IBig($mag0.add($mag1)),
26            (Negative, Positive) => IBig($mag0.add($mag1).with_sign(Negative)),
27            (Negative, Negative) => IBig($mag1.sub_signed($mag0)),
28        }
29    };
30}
31helper_macros::forward_ibig_binop_to_repr!(impl Add, add, Output = IBig, impl_ibig_add);
32helper_macros::forward_ibig_binop_to_repr!(impl Sub, sub, Output = IBig, impl_ibig_sub);
33helper_macros::impl_binop_assign_by_taking!(impl AddAssign<IBig> for IBig, add_assign, add);
34helper_macros::impl_binop_assign_by_taking!(impl SubAssign<IBig> for IBig, sub_assign, sub);
35
36helper_macros::forward_ubig_ibig_binop_to_repr!(impl Add, add, Output = IBig, impl_ibig_add);
37helper_macros::forward_ubig_ibig_binop_to_repr!(impl Sub, sub, Output = IBig, impl_ibig_sub);
38helper_macros::forward_ibig_ubig_binop_to_repr!(impl Add, add, Output = IBig, impl_ibig_add);
39helper_macros::forward_ibig_ubig_binop_to_repr!(impl Sub, sub, Output = IBig, impl_ibig_sub);
40helper_macros::impl_binop_assign_by_taking!(impl AddAssign<UBig> for IBig, add_assign, add);
41helper_macros::impl_binop_assign_by_taking!(impl SubAssign<UBig> for IBig, sub_assign, sub);
42
43// Ops with primitives
44
45macro_rules! impl_add_sub_primitive_with_ubig {
46    ($($t:ty)*) => {$(
47        helper_macros::impl_commutative_binop_with_primitive!(impl Add<$t> for UBig, add);
48        helper_macros::impl_binop_assign_with_primitive!(impl AddAssign<$t> for UBig, add_assign);
49        helper_macros::impl_commutative_binop_with_primitive!(impl Sub<$t> for UBig, sub);
50        helper_macros::impl_binop_assign_with_primitive!(impl SubAssign<$t> for UBig, sub_assign);
51    )*};
52}
53impl_add_sub_primitive_with_ubig!(u8 u16 u32 u64 u128 usize);
54
55macro_rules! impl_add_sub_primitive_with_ibig {
56    ($($t:ty)*) => {$(
57        helper_macros::impl_commutative_binop_with_primitive!(impl Add<$t> for IBig, add);
58        helper_macros::impl_binop_assign_with_primitive!(impl AddAssign<$t> for IBig, add_assign);
59        helper_macros::impl_commutative_binop_with_primitive!(impl Sub<$t> for IBig, sub);
60        helper_macros::impl_binop_assign_with_primitive!(impl SubAssign<$t> for IBig, sub_assign);
61    )*};
62}
63impl_add_sub_primitive_with_ibig!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
64
65pub mod repr {
66    use super::*;
67    use crate::{
68        add,
69        arch::word::{DoubleWord, Word},
70        buffer::Buffer,
71        error::panic_negative_ubig,
72        primitive::split_dword,
73        repr::{
74            Repr,
75            TypedRepr::{self, *},
76            TypedReprRef::{self, *},
77        },
78    };
79
80    impl<'l, 'r> Add<TypedReprRef<'r>> for TypedReprRef<'l> {
81        type Output = Repr;
82        #[inline]
83        fn add(self, rhs: TypedReprRef) -> Repr {
84            match (self, rhs) {
85                (RefSmall(dword0), RefSmall(dword1)) => add_dword(dword0, dword1),
86                (RefSmall(dword0), RefLarge(words1)) => add_large_dword(words1.into(), dword0),
87                (RefLarge(words0), RefSmall(dword1)) => add_large_dword(words0.into(), dword1),
88                (RefLarge(words0), RefLarge(words1)) => {
89                    if words0.len() >= words1.len() {
90                        add_large(words0.into(), words1)
91                    } else {
92                        add_large(words1.into(), words0)
93                    }
94                }
95            }
96        }
97    }
98
99    impl<'l> Add<TypedRepr> for TypedReprRef<'l> {
100        type Output = Repr;
101        #[inline]
102        fn add(self, rhs: TypedRepr) -> Repr {
103            match (self, rhs) {
104                (RefSmall(dword0), Small(dword1)) => add_dword(dword0, dword1),
105                (RefSmall(dword0), Large(buffer1)) => add_large_dword(buffer1, dword0),
106                (RefLarge(words0), Small(dword1)) => add_large_dword(words0.into(), dword1),
107                (RefLarge(words0), Large(buffer1)) => add_large(buffer1, words0),
108            }
109        }
110    }
111
112    impl<'r> Add<TypedReprRef<'r>> for TypedRepr {
113        type Output = Repr;
114        #[inline]
115        fn add(self, rhs: TypedReprRef) -> Repr {
116            // add is commutative
117            rhs.add(self)
118        }
119    }
120
121    impl Add<TypedRepr> for TypedRepr {
122        type Output = Repr;
123        #[inline]
124        fn add(self, rhs: TypedRepr) -> Repr {
125            match (self, rhs) {
126                (Small(dword0), Small(dword1)) => add_dword(dword0, dword1),
127                (Small(dword0), Large(buffer1)) => add_large_dword(buffer1, dword0),
128                (Large(buffer0), Small(dword1)) => add_large_dword(buffer0, dword1),
129                (Large(buffer0), Large(buffer1)) => {
130                    if buffer0.len() >= buffer1.len() {
131                        add_large(buffer0, &buffer1)
132                    } else {
133                        add_large(buffer1, &buffer0)
134                    }
135                }
136            }
137        }
138    }
139
140    #[inline]
141    fn add_dword(a: DoubleWord, b: DoubleWord) -> Repr {
142        let (res, overflow) = a.overflowing_add(b);
143        if overflow {
144            // spilled
145            let (lo, hi) = split_dword(res);
146            let mut buffer = Buffer::allocate(3);
147            buffer.push(lo);
148            buffer.push(hi);
149            buffer.push(1);
150            Repr::from_buffer(buffer)
151        } else {
152            Repr::from_dword(res)
153        }
154    }
155
156    #[inline]
157    fn add_large_dword(mut buffer: Buffer, rhs: DoubleWord) -> Repr {
158        debug_assert!(buffer.len() >= 3);
159        if add::add_dword_in_place(&mut buffer, rhs) {
160            buffer.push_resizing(1);
161        }
162        Repr::from_buffer(buffer)
163    }
164
165    #[inline]
166    fn add_large(mut buffer: Buffer, rhs: &[Word]) -> Repr {
167        let n = buffer.len().min(rhs.len());
168        let overflow = add::add_same_len_in_place(&mut buffer[..n], &rhs[..n]);
169        if rhs.len() > n {
170            buffer.ensure_capacity(rhs.len());
171            buffer.push_slice(&rhs[n..]);
172        }
173        if overflow && add::add_one_in_place(&mut buffer[n..]) {
174            buffer.push_resizing(1);
175        }
176        Repr::from_buffer(buffer)
177    }
178
179    impl<'l, 'r> Sub<TypedReprRef<'r>> for TypedReprRef<'l> {
180        type Output = Repr;
181        #[inline]
182        fn sub(self, rhs: TypedReprRef) -> Repr {
183            match (self, rhs) {
184                (RefSmall(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
185                (RefSmall(_), RefLarge(_)) => panic_negative_ubig(),
186                (RefLarge(buffer0), RefSmall(dword1)) => sub_large_dword(buffer0.into(), dword1),
187                (RefLarge(buffer0), RefLarge(buffer1)) => sub_large(buffer0.into(), buffer1),
188            }
189        }
190    }
191
192    impl<'r> Sub<TypedReprRef<'r>> for TypedRepr {
193        type Output = Repr;
194        #[inline]
195        fn sub(self, rhs: TypedReprRef) -> Repr {
196            match (self, rhs) {
197                (Small(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
198                (Small(_), RefLarge(_)) => panic_negative_ubig(),
199                (Large(buffer0), RefSmall(dword1)) => sub_large_dword(buffer0, dword1),
200                (Large(buffer0), RefLarge(buffer1)) => sub_large(buffer0, buffer1),
201            }
202        }
203    }
204
205    impl<'l> Sub<TypedRepr> for TypedReprRef<'l> {
206        type Output = Repr;
207        #[inline]
208        fn sub(self, rhs: TypedRepr) -> Repr {
209            match (self, rhs) {
210                (RefSmall(dword0), Small(dword1)) => sub_dword(dword0, dword1),
211                (RefSmall(_), Large(_)) => panic_negative_ubig(),
212                (RefLarge(buffer0), Small(dword1)) => sub_large_dword(buffer0.into(), dword1),
213                (RefLarge(buffer0), Large(buffer1)) => sub_large_ref_val(buffer0, buffer1),
214            }
215        }
216    }
217
218    impl Sub<TypedRepr> for TypedRepr {
219        type Output = Repr;
220        #[inline]
221        fn sub(self, rhs: TypedRepr) -> Repr {
222            match (self, rhs) {
223                (Small(dword0), Small(dword1)) => sub_dword(dword0, dword1),
224                (Small(_), Large(_)) => panic_negative_ubig(),
225                (Large(buffer0), Small(dword1)) => sub_large_dword(buffer0, dword1),
226                (Large(buffer0), Large(buffer1)) => sub_large(buffer0, &buffer1),
227            }
228        }
229    }
230
231    #[inline]
232    fn sub_dword(a: DoubleWord, b: DoubleWord) -> Repr {
233        match a.checked_sub(b) {
234            Some(res) => Repr::from_dword(res),
235            None => panic_negative_ubig(),
236        }
237    }
238
239    #[inline]
240    pub(crate) fn sub_large_dword(mut lhs: Buffer, rhs: DoubleWord) -> Repr {
241        let overflow = add::sub_dword_in_place(&mut lhs, rhs);
242        debug_assert!(!overflow);
243        Repr::from_buffer(lhs)
244    }
245
246    #[inline]
247    pub(crate) fn sub_large(mut lhs: Buffer, rhs: &[Word]) -> Repr {
248        if lhs.len() < rhs.len() || add::sub_in_place(&mut lhs, rhs) {
249            panic_negative_ubig();
250        }
251        Repr::from_buffer(lhs)
252    }
253
254    #[inline]
255    pub(crate) fn sub_large_ref_val(lhs: &[Word], mut rhs: Buffer) -> Repr {
256        let n = rhs.len();
257        if lhs.len() < n {
258            panic_negative_ubig();
259        }
260        let borrow = add::sub_same_len_in_place_swap(&lhs[..n], &mut rhs);
261        rhs.ensure_capacity(lhs.len());
262        rhs.push_slice(&lhs[n..]);
263        if borrow && add::sub_one_in_place(&mut rhs[n..]) {
264            panic_negative_ubig();
265        }
266        Repr::from_buffer(rhs)
267    }
268
269    impl<'a> TypedReprRef<'a> {
270        /// Add one to the number
271        pub fn add_one(self) -> Repr {
272            match self {
273                RefSmall(dword) => add_dword(dword, 1),
274                RefLarge(buffer) => add_large_one(buffer.into()),
275            }
276        }
277
278        /// Subtract one from the number
279        pub fn sub_one(self) -> Repr {
280            match self {
281                RefSmall(dword) => Repr::from_dword(dword - 1),
282                RefLarge(buffer) => sub_large_one(buffer.into()),
283            }
284        }
285    }
286
287    impl TypedRepr {
288        /// Add one to the number
289        pub fn add_one(self) -> Repr {
290            match self {
291                Small(dword) => add_dword(dword, 1),
292                Large(buffer) => add_large_one(buffer),
293            }
294        }
295
296        /// Subtract one from the number
297        pub fn sub_one(self) -> Repr {
298            match self {
299                Small(dword) => Repr::from_dword(dword - 1),
300                Large(buffer) => sub_large_one(buffer),
301            }
302        }
303    }
304
305    #[inline]
306    fn add_large_one(mut buffer: Buffer) -> Repr {
307        if add::add_one_in_place(&mut buffer) {
308            buffer.push_resizing(1);
309        }
310        Repr::from_buffer(buffer)
311    }
312
313    #[inline]
314    fn sub_large_one(mut buffer: Buffer) -> Repr {
315        let overflow = add::sub_one_in_place(&mut buffer);
316        debug_assert!(!overflow);
317        Repr::from_buffer(buffer)
318    }
319}
320
321/// This trait is for internal use only, it's used for distinguishing
322/// between subtraction with sign and without sign.
323trait SubSigned<Rhs> {
324    type Output;
325    fn sub_signed(self, rhs: Rhs) -> Self::Output;
326}
327
328mod repr_signed {
329    use super::*;
330    use crate::{
331        add,
332        arch::word::{DoubleWord, Word},
333        buffer::Buffer,
334        repr::{
335            Repr,
336            TypedRepr::{self, *},
337            TypedReprRef::{self, *},
338        },
339    };
340
341    impl<'l, 'r> SubSigned<TypedReprRef<'r>> for TypedReprRef<'l> {
342        type Output = Repr;
343        #[inline]
344        fn sub_signed(self, rhs: TypedReprRef<'r>) -> Repr {
345            match (self, rhs) {
346                (RefSmall(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
347                (RefSmall(dword0), RefLarge(buffer1)) => {
348                    sub_large_dword(buffer1.into(), dword0).neg()
349                }
350                (RefLarge(words0), RefSmall(words1)) => sub_large_dword(words0.into(), words1),
351                (RefLarge(words0), RefLarge(words1)) => {
352                    if words0.len() >= words1.len() {
353                        sub_large(words0.into(), words1)
354                    } else {
355                        sub_large(words1.into(), words0).neg()
356                    }
357                }
358            }
359        }
360    }
361
362    impl<'l> SubSigned<TypedRepr> for TypedReprRef<'l> {
363        type Output = Repr;
364        #[inline]
365        fn sub_signed(self, rhs: TypedRepr) -> Self::Output {
366            match (self, rhs) {
367                (RefSmall(dword0), Small(dword1)) => sub_dword(dword0, dword1),
368                (RefSmall(dword0), Large(buffer1)) => sub_large_dword(buffer1, dword0).neg(),
369                (RefLarge(words0), Small(dword1)) => sub_large_dword(words0.into(), dword1),
370                (RefLarge(words0), Large(buffer1)) => sub_large(buffer1, words0).neg(),
371            }
372        }
373    }
374
375    impl<'r> SubSigned<TypedReprRef<'r>> for TypedRepr {
376        type Output = Repr;
377        #[inline]
378        fn sub_signed(self, rhs: TypedReprRef) -> Self::Output {
379            match (self, rhs) {
380                (Small(dword0), RefSmall(dword1)) => sub_dword(dword0, dword1),
381                (Small(dword0), RefLarge(words1)) => sub_large_dword(words1.into(), dword0).neg(),
382                (Large(buffer0), RefSmall(dword1)) => sub_large_dword(buffer0, dword1),
383                (Large(buffer0), RefLarge(words1)) => sub_large(buffer0, words1),
384            }
385        }
386    }
387
388    impl SubSigned<TypedRepr> for TypedRepr {
389        type Output = Repr;
390        #[inline]
391        fn sub_signed(self, rhs: TypedRepr) -> Self::Output {
392            match (self, rhs) {
393                (Small(dword0), Small(dword1)) => sub_dword(dword0, dword1),
394                (Small(dword0), Large(buffer1)) => sub_large_dword(buffer1, dword0).neg(),
395                (Large(buffer0), Small(dword1)) => sub_large_dword(buffer0, dword1),
396                (Large(buffer0), Large(buffer1)) => {
397                    if buffer0.len() >= buffer1.len() {
398                        sub_large(buffer0, &buffer1)
399                    } else {
400                        sub_large(buffer1, &buffer0).neg()
401                    }
402                }
403            }
404        }
405    }
406
407    #[inline]
408    fn sub_dword(lhs: DoubleWord, rhs: DoubleWord) -> Repr {
409        let (val, overflow) = lhs.overflowing_sub(rhs);
410        if !overflow {
411            Repr::from_dword(val)
412        } else {
413            Repr::from_dword(val.wrapping_neg()).neg()
414        }
415    }
416
417    #[inline]
418    fn sub_large_dword(lhs: Buffer, rhs: DoubleWord) -> Repr {
419        super::repr::sub_large_dword(lhs, rhs)
420    }
421
422    #[inline]
423    fn sub_large(mut lhs: Buffer, rhs: &[Word]) -> Repr {
424        if lhs.len() >= rhs.len() {
425            let sign = add::sub_in_place_with_sign(&mut lhs, rhs);
426            Repr::from_buffer(lhs).with_sign(sign)
427        } else {
428            super::repr::sub_large_ref_val(rhs, lhs).with_sign(Negative)
429        }
430    }
431}