Skip to main content

malachite_nz/integer/logic/
bit_scan.rs

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