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}