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