malachite_nz/integer/arithmetic/
eq_mod_power_of_2.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Copyright © 2001, 2002, 2013 Free Software Foundation, Inc.
6//
7// This file is part of Malachite.
8//
9// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
10// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
11// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
12
13use crate::integer::Integer;
14use crate::natural::InnerNatural::{Large, Small};
15use crate::natural::arithmetic::divisible_by_power_of_2::limbs_divisible_by_power_of_2;
16use crate::natural::{Natural, bit_to_limb_count_floor};
17use crate::platform::Limb;
18use core::cmp::Ordering::*;
19use malachite_base::num::arithmetic::traits::EqModPowerOf2;
20use malachite_base::num::basic::integers::PrimitiveInt;
21
22// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, returns whether
23// the negative of the `Natural` is equivalent to a limb mod two to the power of `pow`; that is,
24// whether the `pow` least-significant bits of the negative of the `Natural` and the limb are equal.
25//
26// This function assumes that `limbs` has length at least 2 and the last (most significant) limb is
27// nonzero.
28//
29// # Worst-case complexity
30// $T(n) = O(n)$
31//
32// $M(n) = O(1)$
33//
34// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
35pub_test! {limbs_eq_mod_power_of_2_neg_limb(xs: &[Limb], y: Limb, pow: u64) -> bool {
36    if y == 0 {
37        return limbs_divisible_by_power_of_2(xs, pow);
38    }
39    let i = bit_to_limb_count_floor(pow);
40    match i.cmp(&xs.len()) {
41        Greater => false,
42        Equal => {
43            if pow & Limb::WIDTH_MASK == 0 {
44                // Check whether the sum of X and y is 0 mod B ^ xs.len().
45                let mut carry = y;
46                for &x in xs {
47                    let sum = x.wrapping_add(carry);
48                    if sum != 0 {
49                        return false;
50                    }
51                    carry = 1;
52                }
53                true
54            } else {
55                false
56            }
57        }
58        Less => {
59            if i == 0 {
60                xs[0].eq_mod_power_of_2(y.wrapping_neg(), pow)
61            } else {
62                xs[0] == y.wrapping_neg()
63                    && xs[1..i].iter().all(|&x| x == Limb::MAX)
64                    && xs[i].eq_mod_power_of_2(Limb::MAX, pow & Limb::WIDTH_MASK)
65            }
66        }
67    }
68}}
69
70fn limbs_eq_mod_power_of_2_neg_pos_greater(xs: &[Limb], ys: &[Limb], pow: u64) -> bool {
71    let xs_len = xs.len();
72    let i = bit_to_limb_count_floor(pow);
73    let small_pow = pow & Limb::WIDTH_MASK;
74    if i > xs_len || i == xs_len && small_pow != 0 {
75        false
76    } else {
77        let ys_len = ys.len();
78        let mut y_nonzero_seen = false;
79        for j in 0..i {
80            let y = if j >= ys_len {
81                Limb::MAX
82            } else if y_nonzero_seen {
83                !ys[j]
84            } else if ys[j] == 0 {
85                0
86            } else {
87                y_nonzero_seen = true;
88                ys[j].wrapping_neg()
89            };
90            if xs[j] != y {
91                return false;
92            }
93        }
94        if small_pow == 0 {
95            true
96        } else {
97            // i < xs_len
98            let y = if i >= ys_len {
99                Limb::MAX
100            } else if y_nonzero_seen {
101                !ys[i]
102            } else {
103                ys[i].wrapping_neg()
104            };
105            xs[i].eq_mod_power_of_2(y, small_pow)
106        }
107    }
108}
109
110// Interpreting two slices of `Limb`s as the limbs (in ascending order) of two `Natural`s, returns
111// whether the first `Natural` and the negative of the second natural (equivalently, the negative of
112// the first `Natural` and the second `Natural`) are equivalent mod two to the power of `pow`; that
113// is, whether their `pow` least-significant bits are equal.
114//
115// This function assumes that neither slice is empty and their last elements are nonzero.
116//
117// # Worst-case complexity
118// $T(n) = O(n)$
119//
120// $M(n) = O(1)$
121//
122// where $T$ is time, $M$ is additional memory, and $n$ is `max(xs.len(), ys.len())`.
123//
124// This is equivalent to `mpz_congruent_2exp_p` from `mpz/cong_2exp.c`, GMP 6.2.1, where `a` is
125// negative and `c` is positive.
126pub_test! {limbs_eq_mod_power_of_2_neg_pos(xs: &[Limb], ys: &[Limb], pow: u64) -> bool {
127    if xs.len() >= ys.len() {
128        limbs_eq_mod_power_of_2_neg_pos_greater(xs, ys, pow)
129    } else {
130        limbs_eq_mod_power_of_2_neg_pos_greater(ys, xs, pow)
131    }
132}}
133
134impl Natural {
135    fn eq_mod_power_of_2_neg_limb(&self, other: Limb, pow: u64) -> bool {
136        match self {
137            Self(Small(small)) => {
138                pow <= Limb::WIDTH && small.wrapping_neg().eq_mod_power_of_2(other, pow)
139            }
140            Self(Large(limbs)) => limbs_eq_mod_power_of_2_neg_limb(limbs, other, pow),
141        }
142    }
143
144    fn eq_mod_power_of_2_neg_pos(&self, other: &Self, pow: u64) -> bool {
145        match (self, other) {
146            (_, &Self(Small(y))) => self.eq_mod_power_of_2_neg_limb(y, pow),
147            (&Self(Small(x)), _) => other.eq_mod_power_of_2_neg_limb(x, pow),
148            (Self(Large(xs)), Self(Large(ys))) => limbs_eq_mod_power_of_2_neg_pos(xs, ys, pow),
149        }
150    }
151}
152
153impl EqModPowerOf2<&Integer> for &Integer {
154    /// Returns whether one [`Integer`] is equal to another modulo $2^k$; that is, whether their $k$
155    /// least-significant bits (in two's complement) are equal.
156    ///
157    /// $f(x, y, k) = (x \equiv y \mod 2^k)$.
158    ///
159    /// $f(x, y, k) = (\exists n \in \Z : x - y = n2^k)$.
160    ///
161    /// # Worst-case complexity
162    /// $T(n) = O(n)$
163    ///
164    /// $M(n) = O(1)$
165    ///
166    /// where $T$ is time, $M$ is additional memory, and $n$ is `min(pow, self.significant_bits(),
167    /// other.significant_bits())`.
168    ///
169    /// # Examples
170    /// ```
171    /// use malachite_base::num::arithmetic::traits::EqModPowerOf2;
172    /// use malachite_base::num::basic::traits::Zero;
173    /// use malachite_nz::integer::Integer;
174    ///
175    /// assert_eq!(
176    ///     Integer::ZERO.eq_mod_power_of_2(&Integer::from(-256), 8),
177    ///     true
178    /// );
179    /// assert_eq!(
180    ///     Integer::from(-0b1101).eq_mod_power_of_2(&Integer::from(0b11011), 3),
181    ///     true
182    /// );
183    /// assert_eq!(
184    ///     Integer::from(-0b1101).eq_mod_power_of_2(&Integer::from(0b11011), 4),
185    ///     false
186    /// );
187    /// ```
188    fn eq_mod_power_of_2(self, other: &Integer, pow: u64) -> bool {
189        if self.sign == other.sign {
190            self.abs.eq_mod_power_of_2(&other.abs, pow)
191        } else {
192            self.abs.eq_mod_power_of_2_neg_pos(&other.abs, pow)
193        }
194    }
195}