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