malachite_nz/integer/logic/bit_scan.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5// Copyright © 2000-2002, 2004, 2012, 2015 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::Natural;
16use crate::natural::logic::bit_scan::{
17 limbs_index_of_next_false_bit, limbs_index_of_next_true_bit,
18};
19use crate::platform::Limb;
20use core::cmp::Ordering::*;
21use malachite_base::num::basic::integers::PrimitiveInt;
22use malachite_base::num::conversion::traits::{ExactFrom, WrappingFrom};
23use malachite_base::num::logic::traits::{BitScan, LowMask, TrailingZeros};
24use malachite_base::slices::slice_leading_zeros;
25
26// Interpreting a slice of `Limb`s as the limbs (in ascending order) of the negative of an
27// `Integer`, finds the lowest index greater than or equal to `starting_index` at which the
28// `Integer` has a `false` bit. If the starting index is too large and there are no more `false`
29// bits above it, `None` is returned.
30//
31// # Worst-case complexity
32// $T(n) = O(n)$
33//
34// $M(n) = O(1)$
35//
36// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
37//
38// This is equivalent to `mpz_scan0` from `mpz/scan0.c`, GMP 6.2.1.
39pub_test! {limbs_index_of_next_false_bit_neg(xs: &[Limb], mut starting_index: u64) -> Option<u64> {
40 let n = xs.len();
41 let i = slice_leading_zeros(xs);
42 assert!(i < n);
43 let starting_limb_index = usize::exact_from(starting_index >> Limb::LOG_WIDTH);
44 if starting_limb_index >= n {
45 return None;
46 }
47 let after_boundary_offset = (u64::wrapping_from(i) + 1) << Limb::LOG_WIDTH;
48 match starting_limb_index.cmp(&i) {
49 Equal => {
50 let within_limb_index = starting_index & Limb::WIDTH_MASK;
51 if let Some(result) = xs[i]
52 .wrapping_neg()
53 .index_of_next_false_bit(within_limb_index)
54 {
55 if result < Limb::WIDTH {
56 return Some((u64::wrapping_from(i) << Limb::LOG_WIDTH) + result);
57 }
58 starting_index = 0;
59 }
60 }
61 Less => {
62 return Some(starting_index);
63 }
64 Greater => {
65 starting_index -= after_boundary_offset;
66 }
67 }
68 limbs_index_of_next_true_bit(&xs[i + 1..], starting_index)
69 .map(|result| result + after_boundary_offset)
70}}
71
72// Interpreting a slice of `Limb`s as the limbs (in ascending order) of the negative of an
73// `Integer`, finds the lowest index greater than or equal to `starting_index` at which the
74// `Integer` has a `true` bit.
75//
76// # Worst-case complexity
77// $T(n) = O(n)$
78//
79// $M(n) = O(1)$
80//
81// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
82//
83// This is equivalent to `mpz_scan1` from `mpz/scan1.c`, GMP 6.2.1.
84pub_test! {limbs_index_of_next_true_bit_neg(xs: &[Limb], mut starting_index: u64) -> u64 {
85 let n = xs.len();
86 let i = slice_leading_zeros(xs);
87 assert!(i < n);
88 let mut starting_limb_index = usize::exact_from(starting_index >> Limb::LOG_WIDTH);
89 if starting_limb_index >= n {
90 return starting_index;
91 }
92 let after_boundary_offset = (u64::wrapping_from(i) + 1) << Limb::LOG_WIDTH;
93 if starting_limb_index < i {
94 starting_index = u64::wrapping_from(i) << Limb::LOG_WIDTH;
95 starting_limb_index = i;
96 }
97 if starting_limb_index == i {
98 let within_limb_index = starting_index & Limb::WIDTH_MASK;
99 if let Some(result) = xs[i]
100 .wrapping_neg()
101 .index_of_next_true_bit(within_limb_index)
102 {
103 return (u64::wrapping_from(i) << Limb::LOG_WIDTH) + result;
104 }
105 starting_index = 0;
106 } else {
107 starting_index -= after_boundary_offset;
108 }
109 limbs_index_of_next_false_bit(&xs[i + 1..], starting_index) + after_boundary_offset
110}}
111
112impl Natural {
113 // self != 0
114 fn index_of_next_false_bit_neg(&self, starting_index: u64) -> Option<u64> {
115 match self {
116 Natural(Small(small)) => {
117 if starting_index >= Limb::WIDTH {
118 None
119 } else {
120 let index = TrailingZeros::trailing_zeros(
121 (small - 1) & !Limb::low_mask(starting_index),
122 );
123 if index == Limb::WIDTH {
124 None
125 } else {
126 Some(index)
127 }
128 }
129 }
130 Natural(Large(limbs)) => limbs_index_of_next_false_bit_neg(limbs, starting_index),
131 }
132 }
133
134 // self != 0
135 fn index_of_next_true_bit_neg(&self, starting_index: u64) -> u64 {
136 match self {
137 Natural(Small(small)) => {
138 if starting_index >= Limb::WIDTH {
139 starting_index
140 } else {
141 TrailingZeros::trailing_zeros(!((small - 1) | Limb::low_mask(starting_index)))
142 }
143 }
144 Natural(Large(limbs)) => limbs_index_of_next_true_bit_neg(limbs, starting_index),
145 }
146 }
147}
148
149impl BitScan for &Integer {
150 /// Given an [`Integer`] and a starting index, searches the [`Integer`] for the smallest index
151 /// of a `false` bit that is greater than or equal to the starting index.
152 ///
153 /// If the [`Integer]` is negative, and the starting index is too large and there are no more
154 /// `false` bits above it, `None` is returned.
155 ///
156 /// # Worst-case complexity
157 /// $T(n) = O(n)$
158 ///
159 /// $M(n) = O(1)$
160 ///
161 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
162 ///
163 /// # Examples
164 /// ```
165 /// use malachite_base::num::logic::traits::BitScan;
166 /// use malachite_nz::integer::Integer;
167 ///
168 /// assert_eq!(
169 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(0),
170 /// Some(0)
171 /// );
172 /// assert_eq!(
173 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(20),
174 /// Some(20)
175 /// );
176 /// assert_eq!(
177 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(31),
178 /// Some(31)
179 /// );
180 /// assert_eq!(
181 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(32),
182 /// Some(34)
183 /// );
184 /// assert_eq!(
185 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(33),
186 /// Some(34)
187 /// );
188 /// assert_eq!(
189 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(34),
190 /// Some(34)
191 /// );
192 /// assert_eq!(
193 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(35),
194 /// None
195 /// );
196 /// assert_eq!(
197 /// (-Integer::from(0x500000000u64)).index_of_next_false_bit(100),
198 /// None
199 /// );
200 /// ```
201 fn index_of_next_false_bit(self, starting_index: u64) -> Option<u64> {
202 if self.sign {
203 self.abs.index_of_next_false_bit(starting_index)
204 } else {
205 self.abs.index_of_next_false_bit_neg(starting_index)
206 }
207 }
208
209 /// Given an [`Integer`] and a starting index, searches the [`Integer`] for the smallest index
210 /// of a `true` bit that is greater than or equal to the starting index.
211 ///
212 /// If the [`Integer`] is non-negative, and the starting index is too large and there are no
213 /// more `true` bits above it, `None` is returned.
214 ///
215 /// # Worst-case complexity
216 /// $T(n) = O(n)$
217 ///
218 /// $M(n) = O(1)$
219 ///
220 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
221 ///
222 /// # Examples
223 /// ```
224 /// use malachite_base::num::logic::traits::BitScan;
225 /// use malachite_nz::integer::Integer;
226 ///
227 /// assert_eq!(
228 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(0),
229 /// Some(32)
230 /// );
231 /// assert_eq!(
232 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(20),
233 /// Some(32)
234 /// );
235 /// assert_eq!(
236 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(31),
237 /// Some(32)
238 /// );
239 /// assert_eq!(
240 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(32),
241 /// Some(32)
242 /// );
243 /// assert_eq!(
244 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(33),
245 /// Some(33)
246 /// );
247 /// assert_eq!(
248 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(34),
249 /// Some(35)
250 /// );
251 /// assert_eq!(
252 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(35),
253 /// Some(35)
254 /// );
255 /// assert_eq!(
256 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(36),
257 /// Some(36)
258 /// );
259 /// assert_eq!(
260 /// (-Integer::from(0x500000000u64)).index_of_next_true_bit(100),
261 /// Some(100)
262 /// );
263 /// ```
264 fn index_of_next_true_bit(self, starting_index: u64) -> Option<u64> {
265 if self.sign {
266 self.abs.index_of_next_true_bit(starting_index)
267 } else {
268 Some(self.abs.index_of_next_true_bit_neg(starting_index))
269 }
270 }
271}