malachite_base/num/arithmetic/
xx_sub_yy_to_zz.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Copyright © 1991-1994, 1996, 1997, 1999-2005, 2007-2009, 2011-2020 Free Software
6//      Foundation, Inc.
7//
8// This file is part of Malachite.
9//
10// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
11// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
12// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
13
14use crate::num::arithmetic::traits::XXSubYYToZZ;
15use crate::num::basic::integers::USIZE_IS_U32;
16use crate::num::basic::unsigneds::PrimitiveUnsigned;
17use crate::num::conversion::traits::{JoinHalves, SplitInHalf, WrappingFrom};
18
19fn implicit_xx_sub_yy_to_zz<DT: JoinHalves + PrimitiveUnsigned + SplitInHalf>(
20    x_1: DT::Half,
21    x_0: DT::Half,
22    y_1: DT::Half,
23    y_0: DT::Half,
24) -> (DT::Half, DT::Half) {
25    DT::join_halves(x_1, x_0)
26        .wrapping_sub(DT::join_halves(y_1, y_0))
27        .split_in_half()
28}
29
30pub_test! {
31explicit_xx_sub_yy_to_zz<T: PrimitiveUnsigned>(x_1: T, x_0: T, y_1: T, y_0: T) -> (T, T) {
32    let (z_0, borrow) = x_0.overflowing_sub(y_0);
33    let mut z_1 = x_1.wrapping_sub(y_1);
34    if borrow {
35        z_1.wrapping_sub_assign(T::ONE);
36    }
37    (z_1, z_0)
38}}
39
40macro_rules! implicit_xx_sub_yy_to_zz {
41    ($t:ident, $dt:ident) => {
42        impl XXSubYYToZZ for $t {
43            /// Subtracts two numbers, each composed of two `Self` values, returning the difference
44            /// as a pair of `Self` values.
45            ///
46            /// The more significant value always comes first. Subtraction is wrapping, and overflow
47            /// is not indicated.
48            ///
49            /// $$
50            /// f(x_1, x_0, y_1, y_0) = (z_1, z_0),
51            /// $$
52            /// where $W$ is `Self::WIDTH`,
53            ///
54            /// $x_1, x_0, y_1, y_0, z_1, z_0 < 2^W$, and
55            /// $$
56            /// (2^Wx_1 + x_0) - (2^Wy_1 + y_0) \equiv 2^Wz_1 + z_0 \mod 2^{2W}.
57            /// $$
58            ///
59            /// # Worst-case complexity
60            /// Constant time and additional memory.
61            ///
62            /// # Examples
63            /// See [here](super::xx_sub_yy_to_zz#xx_sub_yy_to_zz).
64            ///
65            /// This is equivalent to `sub_ddmmss` from `longlong.h`, GMP 6.2.1, where `(sh, sl)` is
66            /// returned.
67            #[inline]
68            fn xx_sub_yy_to_zz(x_1: $t, x_0: $t, y_1: $t, y_0: $t) -> ($t, $t) {
69                implicit_xx_sub_yy_to_zz::<$dt>(x_1, x_0, y_1, y_0)
70            }
71        }
72    };
73}
74
75implicit_xx_sub_yy_to_zz!(u8, u16);
76implicit_xx_sub_yy_to_zz!(u16, u32);
77implicit_xx_sub_yy_to_zz!(u32, u64);
78implicit_xx_sub_yy_to_zz!(u64, u128);
79
80impl XXSubYYToZZ for usize {
81    /// Subtracts two numbers, each composed of two [`usize`] values, returning the difference as a
82    /// pair of [`usize`] values.
83    ///
84    /// The more significant value always comes first. Subtraction is wrapping, and overflow is not
85    /// indicated.
86    ///
87    /// $$
88    /// f(x_1, x_0, y_1, y_0) = (z_1, z_0),
89    /// $$
90    /// where $W$ is `Self::WIDTH`,
91    ///
92    /// $x_1, x_0, y_1, y_0, z_1, z_0 < 2^W$, and
93    /// $$
94    /// (2^Wx_1 + x_0) - (2^Wy_1 + y_0) \equiv 2^Wz_1 + z_0 \mod 2^{2W}.
95    /// $$
96    ///
97    /// # Worst-case complexity
98    /// Constant time and additional memory.
99    ///
100    /// # Examples
101    /// See [here](super::xx_sub_yy_to_zz#xx_sub_yy_to_zz).
102    ///
103    /// This is equivalent to `sub_ddmmss` from `longlong.h`, GMP 6.2.1, where `(sh, sl)` is
104    /// returned.
105    fn xx_sub_yy_to_zz(x_1: usize, x_0: usize, y_1: usize, y_0: usize) -> (usize, usize) {
106        if USIZE_IS_U32 {
107            let (z_1, z_0) = u32::xx_sub_yy_to_zz(
108                u32::wrapping_from(x_1),
109                u32::wrapping_from(x_0),
110                u32::wrapping_from(y_1),
111                u32::wrapping_from(y_0),
112            );
113            (usize::wrapping_from(z_1), usize::wrapping_from(z_0))
114        } else {
115            let (z_1, z_0) = u64::xx_sub_yy_to_zz(
116                u64::wrapping_from(x_1),
117                u64::wrapping_from(x_0),
118                u64::wrapping_from(y_1),
119                u64::wrapping_from(y_0),
120            );
121            (usize::wrapping_from(z_1), usize::wrapping_from(z_0))
122        }
123    }
124}
125
126impl XXSubYYToZZ for u128 {
127    /// Subtracts two numbers, each composed of two [`u128`] values, returning the difference as a
128    /// pair of [`u128`] values.
129    ///
130    /// The more significant value always comes first. Subtraction is wrapping, and overflow is not
131    /// indicated.
132    ///
133    /// $$
134    /// f(x_1, x_0, y_1, y_0) = (z_1, z_0),
135    /// $$
136    /// where $W$ is `Self::WIDTH`,
137    ///
138    /// $x_1, x_0, y_1, y_0, z_1, z_0 < 2^W$, and
139    /// $$
140    /// (2^Wx_1 + x_0) - (2^Wy_1 + y_0) \equiv 2^Wz_1 + z_0 \mod 2^{2W}.
141    /// $$
142    ///
143    /// # Examples
144    /// See [here](super::xx_sub_yy_to_zz#xx_sub_yy_to_zz).
145    ///
146    /// # Worst-case complexity
147    /// Constant time and additional memory.
148    ///
149    /// This is equivalent to `sub_ddmmss` from `longlong.h`, GMP 6.2.1, where `(sh, sl)` is
150    /// returned.
151    #[inline]
152    fn xx_sub_yy_to_zz(x_1: u128, x_0: u128, y_1: u128, y_0: u128) -> (u128, u128) {
153        explicit_xx_sub_yy_to_zz(x_1, x_0, y_1, y_0)
154    }
155}