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}