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}