malachite_base/num/arithmetic/
xxx_add_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::XXXAddYYYToZZZ;
19use crate::num::basic::integers::USIZE_IS_U32;
20use crate::num::basic::unsigneds::PrimitiveUnsigned;
21use crate::num::conversion::traits::WrappingFrom;
22
23pub_test! {xxx_add_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, carry_1) = x_0.overflowing_add(y_0);
32    let (mut z_1, mut carry_2) = x_1.overflowing_add(y_1);
33    if carry_1 {
34        carry_2 |= z_1.overflowing_add_assign(T::ONE);
35    }
36    let mut z_2 = x_2.wrapping_add(y_2);
37    if carry_2 {
38        z_2.wrapping_add_assign(T::ONE);
39    }
40    (z_2, z_1, z_0)
41}}
42
43macro_rules! impl_xxx_add_yyy_to_zzz {
44    ($t:ident) => {
45        impl XXXAddYYYToZZZ for $t {
46            /// Adds two numbers, each composed of three `Self` values, returning the sum as a
47            /// triple of `Self` values.
48            ///
49            /// The more significant value always comes first. Addition is wrapping, and overflow is
50            /// 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_add_yyy_to_zzz#xxx_add_yyy_to_zzz).
68            ///
69            /// This is equivalent to `add_sssaaaaaa` from `longlong.h`, FLINT 2.7.1, where `(sh,
70            /// sm, sl)` is returned.
71            #[inline]
72            fn xxx_add_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_add_yyy_to_zzz::<$t>(x_2, x_1, x_0, y_2, y_1, y_0)
81            }
82        }
83    };
84}
85
86impl_xxx_add_yyy_to_zzz!(u8);
87impl_xxx_add_yyy_to_zzz!(u16);
88impl_xxx_add_yyy_to_zzz!(u32);
89impl_xxx_add_yyy_to_zzz!(u64);
90impl_xxx_add_yyy_to_zzz!(u128);
91
92impl XXXAddYYYToZZZ for usize {
93    /// Adds two numbers, each composed of three [`usize`] values, returning the sum as a triple of
94    /// [`usize`] values.
95    ///
96    /// The more significant value always comes first. Addition 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_add_yyy_to_zzz#xxx_add_yyy_to_zzz).
115    ///
116    /// This is equivalent to `add_sssaaaaaa` from `longlong.h`, FLINT 2.7.1, where `(sh, sm, sl)`
117    /// is returned.
118    fn xxx_add_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_add_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_add_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}