malachite_base/num/arithmetic/xx_div_mod_y_to_qr.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::XXDivModYToQR;
19use crate::num::basic::integers::USIZE_IS_U32;
20use crate::num::basic::unsigneds::PrimitiveUnsigned;
21use crate::num::conversion::half::{wide_join_halves, wide_split_in_half};
22use crate::num::conversion::traits::WrappingFrom;
23use crate::num::conversion::traits::{HasHalf, JoinHalves, SplitInHalf};
24use crate::num::logic::traits::LeadingZeros;
25
26fn implicit_xx_div_mod_y_to_qr<
27 T: PrimitiveUnsigned,
28 DT: From<T> + HasHalf<Half = T> + JoinHalves + PrimitiveUnsigned + SplitInHalf,
29>(
30 x_1: T,
31 x_0: T,
32 y: T,
33) -> (T, T) {
34 assert!(x_1 < y);
35 let (q, r) = DT::join_halves(x_1, x_0).div_mod(DT::from(y));
36 (q.lower_half(), r.lower_half())
37}
38
39// This is equivalent to `udiv_qrnnd_int` from `longlong.h`, FLINT 2.7.1, where `(q, r)` is
40// returned.
41fn explicit_xx_div_mod_y_to_qr_normalized<T: PrimitiveUnsigned>(x_1: T, x_0: T, y: T) -> (T, T) {
42 let (d_1, d_0) = wide_split_in_half(y);
43 let (x_0_1, x_0_0) = wide_split_in_half(x_0);
44 let mut q_1 = x_1 / d_1;
45 let mut r_1 = x_1.wrapping_sub(q_1.wrapping_mul(d_1));
46 let product = q_1.wrapping_mul(d_0);
47 r_1 = wide_join_halves(r_1, x_0_1);
48 if r_1 < product {
49 q_1.wrapping_sub_assign(T::ONE);
50 if !r_1.overflowing_add_assign(y) && r_1 < product {
51 q_1.wrapping_sub_assign(T::ONE);
52 r_1.wrapping_add_assign(y);
53 }
54 }
55 r_1.wrapping_sub_assign(product);
56 let mut q_0 = r_1 / d_1;
57 let mut r_0 = r_1.wrapping_sub(q_0.wrapping_mul(d_1));
58 let product = q_0.wrapping_mul(d_0);
59 r_0 = wide_join_halves(r_0, x_0_0);
60 if r_0 < product {
61 q_0.wrapping_sub_assign(T::ONE);
62 if !r_0.overflowing_add_assign(y) && r_0 < product {
63 q_0.wrapping_sub_assign(T::ONE);
64 r_0.wrapping_add_assign(y);
65 }
66 }
67 r_0.wrapping_sub_assign(product);
68 (wide_join_halves(q_1, q_0), r_0)
69}
70
71// This is udiv_qrnnd from longlong.h, FLINT 2.7.1, where (q, r) is returned.
72pub_test! {explicit_xx_div_mod_y_to_qr<T: PrimitiveUnsigned>(x_1: T, x_0: T, y: T) -> (T, T) {
73 assert!(x_1 < y);
74 let shift = LeadingZeros::leading_zeros(y);
75 if shift == 0 {
76 explicit_xx_div_mod_y_to_qr_normalized(x_1, x_0, y)
77 } else {
78 let (q, r) = explicit_xx_div_mod_y_to_qr_normalized(
79 (x_1 << shift) | (x_0 >> (T::WIDTH - shift)),
80 x_0 << shift,
81 y << shift,
82 );
83 (q, r >> shift)
84 }
85}}
86
87macro_rules! implicit_xx_div_mod_to_qr {
88 ($t:ident, $dt:ident) => {
89 impl XXDivModYToQR for $t {
90 /// Computes the quotient and remainder of two numbers. The first is composed of two
91 /// `Self` values, and the second of a single one.
92 ///
93 /// `x_1` must be less than `y`.
94 ///
95 /// $$
96 /// f(x_1, x_0, y) = (q, r),
97 /// $$
98 /// where $W$ is `Self::WIDTH`,
99 ///
100 /// $x_1, x_0, y, q, r < 2^W$,
101 ///
102 /// $x_1, r < y$, and
103 /// $$
104 /// qy + r = 2^Wx_1 + x_0.
105 /// $$
106 ///
107 /// # Worst-case complexity
108 /// Constant time and additional memory.
109 ///
110 /// # Examples
111 /// See [here](super::xx_div_mod_y_to_qr#xx_div_mod_y_to_qr).
112 ///
113 /// This is equivalent to `udiv_qrnnd` from `longlong.h`, FLINT 2.7.1, where `(q, r)` is
114 /// returned.
115 #[inline]
116 fn xx_div_mod_y_to_qr(x_1: $t, x_0: $t, y: $t) -> ($t, $t) {
117 implicit_xx_div_mod_y_to_qr::<$t, $dt>(x_1, x_0, y)
118 }
119 }
120 };
121}
122
123implicit_xx_div_mod_to_qr!(u8, u16);
124implicit_xx_div_mod_to_qr!(u16, u32);
125implicit_xx_div_mod_to_qr!(u32, u64);
126implicit_xx_div_mod_to_qr!(u64, u128);
127
128impl XXDivModYToQR for usize {
129 /// Computes the quotient and remainder of two numbers. The first is composed of two [`usize`]
130 /// values, and the second of a single one.
131 ///
132 /// `x_1` must be less than `y`.
133 ///
134 /// $$
135 /// f(x_1, x_0, y) = (q, r),
136 /// $$
137 /// where $W$ is `Self::WIDTH`,
138 ///
139 /// $x_1, x_0, y, q, r < 2^W$,
140 ///
141 /// $x_1, r < y$, and
142 /// $$
143 /// qy + r = 2^Wx_1 + x_0.
144 /// $$
145 ///
146 /// # Worst-case complexity
147 /// Constant time and additional memory.
148 ///
149 /// # Examples
150 /// See [here](super::xx_div_mod_y_to_qr#xx_div_mod_y_to_qr).
151 ///
152 /// This is `udiv_qrnnd` from `longlong.h`, FLINT 2.7.1, where `(q, r)` is returned.
153 fn xx_div_mod_y_to_qr(x_1: usize, x_0: usize, y: usize) -> (usize, usize) {
154 if USIZE_IS_U32 {
155 let (q, r) = u32::xx_div_mod_y_to_qr(
156 u32::wrapping_from(x_1),
157 u32::wrapping_from(x_0),
158 u32::wrapping_from(y),
159 );
160 (usize::wrapping_from(q), usize::wrapping_from(r))
161 } else {
162 let (q, r) = u64::xx_div_mod_y_to_qr(
163 u64::wrapping_from(x_1),
164 u64::wrapping_from(x_0),
165 u64::wrapping_from(y),
166 );
167 (usize::wrapping_from(q), usize::wrapping_from(r))
168 }
169 }
170}
171
172impl XXDivModYToQR for u128 {
173 /// Computes the quotient and remainder of two numbers. The first is composed of two [`u128`]
174 /// values, and the second of a single one.
175 ///
176 /// `x_1` must be less than `y`.
177 ///
178 /// $$
179 /// f(x_1, x_0, y) = (q, r),
180 /// $$
181 /// where $W$ is `Self::WIDTH`,
182 ///
183 /// $x_1, x_0, y, q, r < 2^W$,
184 ///
185 /// $x_1, r < y$, and
186 /// $$
187 /// qy + r = 2^Wx_1 + x_0.
188 /// $$
189 ///
190 /// # Worst-case complexity
191 /// Constant time and additional memory.
192 ///
193 /// # Examples
194 /// See [here](super::xx_div_mod_y_to_qr#xx_div_mod_y_to_qr).
195 ///
196 /// This is equivalent to `udiv_qrnnd` from `longlong.h`, FLINT 2.7.1, where `(q, r)` is
197 /// returned.
198 #[inline]
199 fn xx_div_mod_y_to_qr(x_1: u128, x_0: u128, y: u128) -> (u128, u128) {
200 explicit_xx_div_mod_y_to_qr(x_1, x_0, y)
201 }
202}