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