malachite_nz/integer/logic/
bit_access.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MP Library.
4//
5//      Copyright © 1991, 1993-1995, 1997, 1999, 2000, 2001, 2002, 2012 Free Software Foundation,
6//      Inc.
7//
8// This file is part of Malachite.
9//
10// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
11// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
12// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
13
14use crate::integer::Integer;
15use crate::natural::InnerNatural::{Large, Small};
16use crate::natural::arithmetic::add::limbs_slice_add_limb_in_place;
17use crate::natural::arithmetic::sub::limbs_sub_limb_in_place;
18use crate::natural::{Natural, bit_to_limb_count_floor};
19use crate::platform::Limb;
20use alloc::vec::Vec;
21use core::cmp::Ordering::*;
22use malachite_base::num::arithmetic::traits::{PowerOf2, WrappingAddAssign, WrappingNegAssign};
23use malachite_base::num::basic::integers::PrimitiveInt;
24use malachite_base::num::logic::traits::BitAccess;
25use malachite_base::slices::{slice_leading_zeros, slice_test_zero};
26
27// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, performs an
28// action equivalent to taking the two's complement of the limbs and getting the bit at the
29// specified index. Sufficiently high indices will return `true`. The slice cannot be empty or
30// contain only zeros.
31//
32// # Worst-case complexity
33// $T(n) = O(n)$
34//
35// $M(n) = O(1)$
36//
37// where $T$ is time, $M$ is additional memory, and $n$ is `xs.len()`.
38//
39// This is equivalent to `mpz_tstbit` from `mpz/tstbit.c`, GMP 6.2.1, where `d` is negative.
40pub_test! {limbs_get_bit_neg(xs: &[Limb], index: u64) -> bool {
41    let x_i = bit_to_limb_count_floor(index);
42    if x_i >= xs.len() {
43        // We're indexing into the infinite suffix of 1s
44        true
45    } else {
46        let x = if slice_test_zero(&xs[..x_i]) {
47            xs[x_i].wrapping_neg()
48        } else {
49            !xs[x_i]
50        };
51        x.get_bit(index & Limb::WIDTH_MASK)
52    }
53}}
54
55// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, performs an
56// action equivalent to taking the two's complement of the limbs, setting a bit at the specified
57// index to `true`, and taking the two's complement again. Indices that are outside the bounds of
58// the slice will result in no action being taken, since negative numbers in two's complement have
59// infinitely many leading 1s. The slice cannot be empty or contain only zeros.
60//
61// # Worst-case complexity
62// $T(n) = O(n)$
63//
64// $M(n) = O(1)$
65//
66// where $T$ is time, $M$ is additional memory, and $n$ is `index`.
67//
68// # Panics
69// If the slice contains only zeros a panic may occur.
70//
71// This is equivalent to `mpz_setbit` from `mpz/setbit.c`, GMP 6.2.1, where `d` is negative.
72pub_test! {limbs_set_bit_neg(xs: &mut [Limb], index: u64) {
73    let x_i = bit_to_limb_count_floor(index);
74    if x_i >= xs.len() {
75        return;
76    }
77    let reduced_index = index & Limb::WIDTH_MASK;
78    let zero_bound = slice_leading_zeros(xs);
79    match x_i.cmp(&zero_bound) {
80        Equal => {
81            let boundary = &mut xs[x_i];
82            // boundary != 0 here
83            *boundary -= 1;
84            boundary.clear_bit(reduced_index);
85            // boundary != Limb::MAX here
86            *boundary += 1;
87        }
88        Less => {
89            assert!(!limbs_sub_limb_in_place(
90                &mut xs[x_i..],
91                Limb::power_of_2(reduced_index),
92            ));
93        }
94        Greater => {
95            xs[x_i].clear_bit(reduced_index);
96        }
97    }
98}}
99
100fn limbs_clear_bit_neg_helper(xs: &mut [Limb], x_i: usize, reduced_index: u64) -> bool {
101    let zero_bound = slice_leading_zeros(xs);
102    match x_i.cmp(&zero_bound) {
103        Equal => {
104            // xs[x_i] != 0 here
105            let mut boundary = xs[x_i] - 1;
106            boundary.set_bit(reduced_index);
107            boundary.wrapping_add_assign(1);
108            xs[x_i] = boundary;
109            boundary == 0 && limbs_slice_add_limb_in_place(&mut xs[x_i + 1..], 1)
110        }
111        Greater => {
112            xs[x_i].set_bit(reduced_index);
113            false
114        }
115        _ => false,
116    }
117}
118
119// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, performs an
120// action equivalent to taking the two's complement of the limbs, setting a bit at the specified
121// index to `false`, and taking the two's complement again. Inputs that would result in new `true`
122// bits outside of the slice will cause a panic. The slice cannot be empty or contain only zeros.
123//
124// # Worst-case complexity
125// $T(n) = O(n)$
126//
127// $M(n) = O(1)$
128//
129// where $T$ is time, $M$ is additional memory, and $n$ is `index`.
130//
131// # Panics
132// Panics if evaluation would require new `true` bits outside of the slice. If the slice contains
133// only zeros a panic may occur.
134//
135// This is equivalent to `mpz_clrbit` from `mpz/clrbit.c`, GMP 6.2.1, where `d` is negative and
136// `bit_idx` small enough that no additional memory needs to be given to `d`.
137pub fn limbs_slice_clear_bit_neg(xs: &mut [Limb], index: u64) {
138    let x_i = bit_to_limb_count_floor(index);
139    let reduced_index = index & Limb::WIDTH_MASK;
140    assert!(
141        x_i < xs.len() && !limbs_clear_bit_neg_helper(xs, x_i, reduced_index),
142        "Setting bit cannot be done within existing slice"
143    );
144}
145
146// Interpreting a `Vec` of `Limb`s as the limbs (in ascending order) of a `Natural`, performs an
147// action equivalent to taking the two's complement of the limbs, setting a bit at the specified
148// index to `false`, and taking the two's complement again. Sufficiently high indices will increase
149// the length of the limbs vector. The slice cannot be empty or contain only zeros.
150//
151// # Worst-case complexity
152// $T(n) = O(n)$
153//
154// $M(n) = O(n)$
155//
156// where $T$ is time, $M$ is additional memory, and $n$ is `index`.
157//
158// # Panics
159// If the slice contains only zeros a panic may occur.
160//
161// This is equivalent to `mpz_clrbit` from `mpz/clrbit.c`, GMP 6.2.1, where `d` is negative.
162pub_test! {limbs_vec_clear_bit_neg(xs: &mut Vec<Limb>, index: u64) {
163    let x_i = bit_to_limb_count_floor(index);
164    let reduced_index = index & Limb::WIDTH_MASK;
165    if x_i < xs.len() {
166        if limbs_clear_bit_neg_helper(xs, x_i, reduced_index) {
167            xs.push(1);
168        }
169    } else {
170        xs.resize(x_i, 0);
171        xs.push(Limb::power_of_2(reduced_index));
172    }
173}}
174
175impl Natural {
176    // self cannot be zero
177    pub(crate) fn get_bit_neg(&self, index: u64) -> bool {
178        match self {
179            Self(Small(small)) => index >= Limb::WIDTH || small.wrapping_neg().get_bit(index),
180            Self(Large(limbs)) => limbs_get_bit_neg(limbs, index),
181        }
182    }
183
184    // self cannot be zero
185    fn set_bit_neg(&mut self, index: u64) {
186        match self {
187            Self(Small(small)) => {
188                if index < Limb::WIDTH {
189                    small.wrapping_neg_assign();
190                    small.set_bit(index);
191                    small.wrapping_neg_assign();
192                }
193            }
194            Self(Large(limbs)) => {
195                limbs_set_bit_neg(limbs, index);
196                self.trim();
197            }
198        }
199    }
200
201    // self cannot be zero
202    fn clear_bit_neg(&mut self, index: u64) {
203        match self {
204            Self(Small(small)) if index < Limb::WIDTH => {
205                let mut cleared_small = small.wrapping_neg();
206                cleared_small.clear_bit(index);
207                if cleared_small == 0 {
208                    *self = Self(Large(vec![0, 1]));
209                } else {
210                    *small = cleared_small.wrapping_neg();
211                }
212            }
213            Self(Small(_)) => {
214                let limbs = self.promote_in_place();
215                limbs_vec_clear_bit_neg(limbs, index);
216            }
217            Self(Large(limbs)) => {
218                limbs_vec_clear_bit_neg(limbs, index);
219            }
220        }
221    }
222}
223
224/// Provides functions for accessing and modifying the $i$th bit of a [`Integer`], or the
225/// coefficient of $2^i$ in its two's complement binary expansion.
226///
227/// # Examples
228/// ```
229/// use malachite_base::num::basic::traits::{NegativeOne, Zero};
230/// use malachite_base::num::logic::traits::BitAccess;
231/// use malachite_nz::integer::Integer;
232///
233/// let mut x = Integer::ZERO;
234/// x.assign_bit(2, true);
235/// x.assign_bit(5, true);
236/// x.assign_bit(6, true);
237/// assert_eq!(x, 100);
238/// x.assign_bit(2, false);
239/// x.assign_bit(5, false);
240/// x.assign_bit(6, false);
241/// assert_eq!(x, 0);
242///
243/// let mut x = Integer::from(-0x100);
244/// x.assign_bit(2, true);
245/// x.assign_bit(5, true);
246/// x.assign_bit(6, true);
247/// assert_eq!(x, -156);
248/// x.assign_bit(2, false);
249/// x.assign_bit(5, false);
250/// x.assign_bit(6, false);
251/// assert_eq!(x, -256);
252///
253/// let mut x = Integer::ZERO;
254/// x.flip_bit(10);
255/// assert_eq!(x, 1024);
256/// x.flip_bit(10);
257/// assert_eq!(x, 0);
258///
259/// let mut x = Integer::NEGATIVE_ONE;
260/// x.flip_bit(10);
261/// assert_eq!(x, -1025);
262/// x.flip_bit(10);
263/// assert_eq!(x, -1);
264/// ```
265impl BitAccess for Integer {
266    /// Determines whether the $i$th bit of an [`Integer`], or the coefficient of $2^i$ in its two's
267    /// complement binary expansion, is 0 or 1.
268    ///
269    /// `false` means 0 and `true` means 1. Getting bits beyond the [`Integer`]'s width is allowed;
270    /// those bits are `false` if the [`Integer`] is non-negative and `true` if it is negative.
271    ///
272    /// If $n \geq 0$, let
273    /// $$
274    /// n = \sum_{i=0}^\infty 2^{b_i};
275    /// $$
276    /// but if $n < 0$, let
277    /// $$
278    /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
279    /// $$
280    /// where for all $i$, $b_i\in \\{0, 1\\}$.
281    ///
282    /// $f(n, i) = (b_i = 1)$.
283    ///
284    /// # Worst-case complexity
285    /// $T(n) = O(n)$
286    ///
287    /// $M(n) = O(1)$
288    ///
289    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
290    ///
291    /// # Examples
292    /// ```
293    /// use malachite_base::num::arithmetic::traits::Pow;
294    /// use malachite_base::num::logic::traits::BitAccess;
295    /// use malachite_nz::integer::Integer;
296    ///
297    /// assert_eq!(Integer::from(123).get_bit(2), false);
298    /// assert_eq!(Integer::from(123).get_bit(3), true);
299    /// assert_eq!(Integer::from(123).get_bit(100), false);
300    /// assert_eq!(Integer::from(-123).get_bit(0), true);
301    /// assert_eq!(Integer::from(-123).get_bit(1), false);
302    /// assert_eq!(Integer::from(-123).get_bit(100), true);
303    /// assert_eq!(Integer::from(10u32).pow(12).get_bit(12), true);
304    /// assert_eq!(Integer::from(10u32).pow(12).get_bit(100), false);
305    /// assert_eq!((-Integer::from(10u32).pow(12)).get_bit(12), true);
306    /// assert_eq!((-Integer::from(10u32).pow(12)).get_bit(100), true);
307    /// ```
308    fn get_bit(&self, index: u64) -> bool {
309        match self {
310            Self { sign: true, abs } => abs.get_bit(index),
311            Self { sign: false, abs } => abs.get_bit_neg(index),
312        }
313    }
314
315    /// Sets the $i$th bit of an [`Integer`], or the coefficient of $2^i$ in its two's complement
316    /// binary expansion, to 1.
317    ///
318    /// If $n \geq 0$, let
319    /// $$
320    /// n = \sum_{i=0}^\infty 2^{b_i};
321    /// $$
322    /// but if $n < 0$, let
323    /// $$
324    /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
325    /// $$
326    /// where for all $i$, $b_i\in \\{0, 1\\}$.
327    /// $$
328    /// n \gets \\begin{cases}
329    ///     n + 2^j & \text{if} \\quad b_j = 0, \\\\
330    ///     n & \text{otherwise}.
331    /// \\end{cases}
332    /// $$
333    ///
334    /// # Worst-case complexity
335    /// $T(n) = O(n)$
336    ///
337    /// $M(n) = O(n)$
338    ///
339    /// where $T$ is time, $M$ is additional memory, and $n$ is `index`.
340    ///
341    /// # Examples
342    /// ```
343    /// use malachite_base::num::basic::traits::Zero;
344    /// use malachite_base::num::logic::traits::BitAccess;
345    /// use malachite_nz::integer::Integer;
346    ///
347    /// let mut x = Integer::ZERO;
348    /// x.set_bit(2);
349    /// x.set_bit(5);
350    /// x.set_bit(6);
351    /// assert_eq!(x, 100);
352    ///
353    /// let mut x = Integer::from(-0x100);
354    /// x.set_bit(2);
355    /// x.set_bit(5);
356    /// x.set_bit(6);
357    /// assert_eq!(x, -156);
358    /// ```
359    fn set_bit(&mut self, index: u64) {
360        match self {
361            Self { sign: true, abs } => abs.set_bit(index),
362            Self { sign: false, abs } => abs.set_bit_neg(index),
363        }
364    }
365
366    /// Sets the $i$th bit of an [`Integer`], or the coefficient of $2^i$ in its binary expansion,
367    /// to 0.
368    ///
369    /// If $n \geq 0$, let
370    /// $$
371    /// n = \sum_{i=0}^\infty 2^{b_i};
372    /// $$
373    /// but if $n < 0$, let
374    /// $$
375    /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
376    /// $$
377    /// where for all $i$, $b_i\in \\{0, 1\\}$.
378    /// $$
379    /// n \gets \\begin{cases}
380    ///     n - 2^j & \text{if} \\quad b_j = 1, \\\\
381    ///     n & \text{otherwise}.
382    /// \\end{cases}
383    /// $$
384    ///
385    /// # Worst-case complexity
386    /// $T(n) = O(n)$
387    ///
388    /// $M(n) = O(n)$
389    ///
390    /// where $T$ is time, $M$ is additional memory, and $n$ is `index`.
391    ///
392    /// # Examples
393    /// ```
394    /// use malachite_base::num::logic::traits::BitAccess;
395    /// use malachite_nz::integer::Integer;
396    ///
397    /// let mut x = Integer::from(0x7f);
398    /// x.clear_bit(0);
399    /// x.clear_bit(1);
400    /// x.clear_bit(3);
401    /// x.clear_bit(4);
402    /// assert_eq!(x, 100);
403    ///
404    /// let mut x = Integer::from(-156);
405    /// x.clear_bit(2);
406    /// x.clear_bit(5);
407    /// x.clear_bit(6);
408    /// assert_eq!(x, -256);
409    /// ```
410    fn clear_bit(&mut self, index: u64) {
411        match self {
412            Self { sign: true, abs } => abs.clear_bit(index),
413            Self { sign: false, abs } => abs.clear_bit_neg(index),
414        }
415    }
416}