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