malachite_nz/integer/logic/
bit_block_access.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::integer::Integer;
10use crate::integer::conversion::to_twos_complement_limbs::limbs_twos_complement_in_place;
11use crate::natural::InnerNatural::{Large, Small};
12use crate::natural::Natural;
13use crate::natural::arithmetic::add::limbs_vec_add_limb_in_place;
14use crate::natural::arithmetic::mod_power_of_2::limbs_vec_mod_power_of_2_in_place;
15use crate::natural::arithmetic::shr::limbs_slice_shr_in_place;
16use crate::natural::arithmetic::sub::limbs_sub_limb_in_place;
17use crate::natural::logic::bit_block_access::limbs_assign_bits_helper;
18use crate::natural::logic::not::limbs_not_in_place;
19use crate::natural::logic::trailing_zeros::limbs_trailing_zeros;
20use crate::platform::Limb;
21use alloc::vec::Vec;
22use malachite_base::num::arithmetic::traits::{ModPowerOf2, ShrRound};
23use malachite_base::num::basic::integers::PrimitiveInt;
24use malachite_base::num::conversion::traits::ExactFrom;
25use malachite_base::num::logic::traits::{BitBlockAccess, LeadingZeros, TrailingZeros};
26use malachite_base::rounding_modes::RoundingMode::*;
27use malachite_base::vecs::vec_delete_left;
28
29// Returns the limbs obtained by taking a slice of bits beginning at index `start` of the negative
30// of `limb` and ending at index `end - 1`. `start` must be less than or equal to `end`, but apart
31// from that there are no restrictions on the index values. If they index beyond the physical size
32// of the input limbs, the function interprets them as pointing to `true` bits. `x` must be
33// positive.
34//
35// # Worst-case complexity
36// $T(n) = O(n)$
37//
38// $M(n) = O(n)$
39//
40// where $T$ is time, $M$ is additional memory and $n$ is `end`.
41//
42// # Panics
43// Panics if `start > end`.
44pub_test! {limbs_neg_limb_get_bits(x: Limb, start: u64, end: u64) -> Vec<Limb> {
45    assert!(start <= end);
46    let trailing_zeros = TrailingZeros::trailing_zeros(x);
47    if trailing_zeros >= end {
48        return Vec::new();
49    }
50    let bit_len = end - start;
51    let mut out = if start >= Limb::WIDTH {
52        vec![
53            Limb::MAX;
54            usize::exact_from(bit_len.shr_round(Limb::LOG_WIDTH, Ceiling).0)
55        ]
56    } else {
57        let mut out = vec![x >> start];
58        out.resize(usize::exact_from(end >> Limb::LOG_WIDTH) + 1, 0);
59        if trailing_zeros >= start {
60            limbs_twos_complement_in_place(&mut out);
61        } else {
62            limbs_not_in_place(&mut out);
63        }
64        out
65    };
66    limbs_vec_mod_power_of_2_in_place(&mut out, bit_len);
67    out
68}}
69
70// Interpreting a slice of `Limb`s as the limbs (in ascending order) of a `Natural`, returns the
71// limbs obtained by taking a slice of bits beginning at index `start` of the negative of the
72// `Natural` and ending at index `end - 1`. `start` must be less than or equal to `end`, but apart
73// from that there are no restrictions on the index values. If they index beyond the physical size
74// of the input limbs, the function interprets them as pointing to `true` bits. The input slice
75// cannot only contain zeros.
76//
77// # Worst-case complexity
78// $T(n) = O(n)$
79//
80// $M(n) = O(n)$
81//
82// where $T$ is time, $M$ is additional memory and $n$ is `max(xs.len(), end * Limb::WIDTH)`.
83//
84// # Panics
85// Panics if `start > end`.
86pub_test! {limbs_slice_neg_get_bits(xs: &[Limb], start: u64, end: u64) -> Vec<Limb> {
87    assert!(start <= end);
88    let trailing_zeros = limbs_trailing_zeros(xs);
89    if trailing_zeros >= end {
90        return Vec::new();
91    }
92    let start_i = usize::exact_from(start >> Limb::LOG_WIDTH);
93    let len = xs.len();
94    let bit_len = end - start;
95    if start_i >= len {
96        let mut out =
97            vec![
98                Limb::MAX;
99                usize::exact_from(bit_len.shr_round(Limb::LOG_WIDTH, Ceiling).0)
100            ];
101        limbs_vec_mod_power_of_2_in_place(&mut out, bit_len);
102        return out;
103    }
104    let end_i = usize::exact_from(end >> Limb::LOG_WIDTH) + 1;
105    let mut out = (if end_i >= len {
106        &xs[start_i..]
107    } else {
108        &xs[start_i..end_i]
109    })
110    .to_vec();
111    let offset = start & Limb::WIDTH_MASK;
112    if offset != 0 {
113        limbs_slice_shr_in_place(&mut out, offset);
114    }
115    out.resize(end_i - start_i, 0);
116    if trailing_zeros >= start {
117        limbs_twos_complement_in_place(&mut out);
118    } else {
119        limbs_not_in_place(&mut out);
120    }
121    limbs_vec_mod_power_of_2_in_place(&mut out, bit_len);
122    out
123}}
124
125// Interpreting a `Vec` of `Limb`s as the limbs (in ascending order) of a `Natural`, returns the
126// limbs obtained by taking a slice of bits beginning at index `start` of the negative of the
127// `Natural` and ending at index `end - 1`. `start` must be less than or equal to `end`, but apart
128// from that there are no restrictions on the index values. If they index beyond the physical size
129// of the input limbs, the function interprets them as pointing to `true` bits. The input slice
130// cannot only contain zeros.
131//
132// # Worst-case complexity
133// $T(n) = O(n)$
134//
135// $M(n) = O(n)$
136//
137// where $T$ is time, $M$ is additional memory and $n$ is `max(xs.len(), end * Limb::WIDTH)`.
138//
139// # Panics
140// Panics if `start > end`.
141pub_test! {limbs_vec_neg_get_bits(mut xs: Vec<Limb>, start: u64, end: u64) -> Vec<Limb> {
142    assert!(start <= end);
143    let trailing_zeros = limbs_trailing_zeros(&xs);
144    if trailing_zeros >= end {
145        return Vec::new();
146    }
147    let start_i = usize::exact_from(start >> Limb::LOG_WIDTH);
148    let len = xs.len();
149    let bit_len = end - start;
150    if start_i >= len {
151        xs = vec![
152            Limb::MAX;
153            usize::exact_from(bit_len.shr_round(Limb::LOG_WIDTH, Ceiling).0)
154        ];
155        limbs_vec_mod_power_of_2_in_place(&mut xs, bit_len);
156        return xs;
157    }
158    let end_i = usize::exact_from(end >> Limb::LOG_WIDTH) + 1;
159    xs.truncate(end_i);
160    vec_delete_left(&mut xs, start_i);
161    let offset = start & Limb::WIDTH_MASK;
162    if offset != 0 {
163        limbs_slice_shr_in_place(&mut xs, offset);
164    }
165    xs.resize(end_i - start_i, 0);
166    if trailing_zeros >= start {
167        limbs_twos_complement_in_place(&mut xs);
168    } else {
169        limbs_not_in_place(&mut xs);
170    }
171    limbs_vec_mod_power_of_2_in_place(&mut xs, bit_len);
172    xs
173}}
174
175// Interpreting a `Vec` of `Limb`s as the limbs (in ascending order) of a `Natural` n, writes the
176// limbs of `bits` into the limbs of -n, starting at bit `start` of -n (inclusive) and ending at bit
177// `end` of -n (exclusive). The bit indices do not need to be aligned with any limb boundaries. If
178// `bits` has more than `end` - `start` bits, only the first `end` - `start` bits are written. If
179// `bits` has fewer than `end` - `start` bits, the remaining written bits are one. `xs` may be
180// extended to accommodate the new bits. `start` must be smaller than `end`, and `xs` cannot only
181// contain zeros.
182//
183// # Worst-case complexity
184// $T(n) = O(n)$
185//
186// $M(m) = O(m)$
187//
188// where $T$ is time, $M$ is additional memory, $n$ is `max(n / 2 ^ Limb::WIDTH, m)`, and $m$ is
189// `end`.
190//
191// # Panics
192// Panics if `start >= end` or `xs` only contains zeros.
193pub_test! {limbs_neg_assign_bits(xs: &mut Vec<Limb>, start: u64, end: u64, bits: &[Limb]) {
194    assert!(start < end);
195    assert!(!limbs_sub_limb_in_place(xs, 1));
196    limbs_assign_bits_helper(xs, start, end, bits, true);
197    limbs_vec_add_limb_in_place(xs, 1);
198}}
199
200impl Natural {
201    fn neg_get_bits(&self, start: u64, end: u64) -> Natural {
202        Natural::from_owned_limbs_asc(match self {
203            Natural(Small(small)) => limbs_neg_limb_get_bits(*small, start, end),
204            Natural(Large(limbs)) => limbs_slice_neg_get_bits(limbs, start, end),
205        })
206    }
207
208    fn neg_get_bits_owned(self, start: u64, end: u64) -> Natural {
209        Natural::from_owned_limbs_asc(match self {
210            Natural(Small(small)) => limbs_neg_limb_get_bits(small, start, end),
211            Natural(Large(limbs)) => limbs_vec_neg_get_bits(limbs, start, end),
212        })
213    }
214
215    fn neg_assign_bits(&mut self, start: u64, end: u64, bits: &Natural) {
216        if start == end {
217            return;
218        }
219        let bits_width = end - start;
220        if bits_width <= Limb::WIDTH {
221            if let (&mut Natural(Small(ref mut small_self)), &Natural(Small(small_bits))) =
222                (&mut *self, bits)
223            {
224                let small_bits = (!small_bits).mod_power_of_2(bits_width);
225                if small_bits == 0 || LeadingZeros::leading_zeros(small_bits) >= start {
226                    let mut new_small_self = *small_self - 1;
227                    new_small_self.assign_bits(start, end, &small_bits);
228                    let (sum, overflow) = new_small_self.overflowing_add(1);
229                    if !overflow {
230                        *small_self = sum;
231                        return;
232                    }
233                }
234            }
235        }
236        let limbs = self.promote_in_place();
237        match bits {
238            Natural(Small(small_bits)) => limbs_neg_assign_bits(limbs, start, end, &[*small_bits]),
239            Natural(Large(bits_limbs)) => limbs_neg_assign_bits(limbs, start, end, bits_limbs),
240        }
241        self.trim();
242    }
243}
244
245impl BitBlockAccess for Integer {
246    type Bits = Natural;
247
248    /// Extracts a block of adjacent two's complement bits from an [`Integer`], taking the
249    /// [`Integer`] by reference.
250    ///
251    /// The first index is `start` and last index is `end - 1`.
252    ///
253    /// Let $n$ be `self`, and let $p$ and $q$ be `start` and `end`, respectively.
254    ///
255    /// If $n \geq 0$, let
256    /// $$
257    /// n = \sum_{i=0}^\infty 2^{b_i};
258    /// $$
259    /// but if $n < 0$, let
260    /// $$
261    /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
262    /// $$
263    /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
264    /// $$
265    /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
266    /// $$
267    ///
268    /// # Worst-case complexity
269    /// $T(n) = O(n)$
270    ///
271    /// $M(n) = O(n)$
272    ///
273    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(), end)`.
274    ///
275    /// # Panics
276    /// Panics if `start > end`.
277    ///
278    /// # Examples
279    /// ```
280    /// use core::str::FromStr;
281    /// use malachite_base::num::basic::traits::Zero;
282    /// use malachite_base::num::logic::traits::BitBlockAccess;
283    /// use malachite_nz::integer::Integer;
284    /// use malachite_nz::natural::Natural;
285    ///
286    /// assert_eq!(
287    ///     (-Natural::from(0xabcdef0112345678u64)).get_bits(16, 48),
288    ///     Natural::from(0x10feedcbu32)
289    /// );
290    /// assert_eq!(
291    ///     Integer::from(0xabcdef0112345678u64).get_bits(4, 16),
292    ///     Natural::from(0x567u32)
293    /// );
294    /// assert_eq!(
295    ///     (-Natural::from(0xabcdef0112345678u64)).get_bits(0, 100),
296    ///     Natural::from_str("1267650600215849587758112418184").unwrap()
297    /// );
298    /// assert_eq!(
299    ///     Integer::from(0xabcdef0112345678u64).get_bits(10, 10),
300    ///     Natural::ZERO
301    /// );
302    /// ```
303    fn get_bits(&self, start: u64, end: u64) -> Natural {
304        if self.sign {
305            self.abs.get_bits(start, end)
306        } else {
307            self.abs.neg_get_bits(start, end)
308        }
309    }
310
311    /// Extracts a block of adjacent two's complement bits from an [`Integer`], taking the
312    /// [`Integer`] by value.
313    ///
314    /// The first index is `start` and last index is `end - 1`.
315    ///
316    /// Let $n$ be `self`, and let $p$ and $q$ be `start` and `end`, respectively.
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\\}$. Then
327    /// $$
328    /// f(n, p, q) = \sum_{i=p}^{q-1} 2^{b_{i-p}}.
329    /// $$
330    ///
331    /// # Worst-case complexity
332    /// $T(n) = O(n)$
333    ///
334    /// $M(n) = O(n)$
335    ///
336    /// where $T$ is time, $M$ is additional memory, and $n$ is `max(self.significant_bits(), end)`.
337    ///
338    /// # Panics
339    /// Panics if `start > end`.
340    ///
341    /// # Examples
342    /// ```
343    /// use core::str::FromStr;
344    /// use malachite_base::num::basic::traits::Zero;
345    /// use malachite_base::num::logic::traits::BitBlockAccess;
346    /// use malachite_nz::integer::Integer;
347    /// use malachite_nz::natural::Natural;
348    ///
349    /// assert_eq!(
350    ///     (-Natural::from(0xabcdef0112345678u64)).get_bits_owned(16, 48),
351    ///     Natural::from(0x10feedcbu32)
352    /// );
353    /// assert_eq!(
354    ///     Integer::from(0xabcdef0112345678u64).get_bits_owned(4, 16),
355    ///     Natural::from(0x567u32)
356    /// );
357    /// assert_eq!(
358    ///     (-Natural::from(0xabcdef0112345678u64)).get_bits_owned(0, 100),
359    ///     Natural::from_str("1267650600215849587758112418184").unwrap()
360    /// );
361    /// assert_eq!(
362    ///     Integer::from(0xabcdef0112345678u64).get_bits_owned(10, 10),
363    ///     Natural::ZERO
364    /// );
365    /// ```
366    fn get_bits_owned(self, start: u64, end: u64) -> Natural {
367        if self.sign {
368            self.abs.get_bits_owned(start, end)
369        } else {
370            self.abs.neg_get_bits_owned(start, end)
371        }
372    }
373
374    /// Replaces a block of adjacent two's complement bits in an [`Integer`] with other bits.
375    ///
376    /// The least-significant `end - start` bits of `bits` are assigned to bits `start` through `end
377    /// - 1`, inclusive, of `self`.
378    ///
379    /// Let $n$ be `self` and let $m$ be `bits`, and let $p$ and $q$ be `start` and `end`,
380    /// respectively.
381    ///
382    /// Let
383    /// $$
384    /// m = \sum_{i=0}^k 2^{d_i},
385    /// $$
386    /// where for all $i$, $d_i\in \\{0, 1\\}$.
387    ///
388    /// If $n \geq 0$, let
389    /// $$
390    /// n = \sum_{i=0}^\infty 2^{b_i};
391    /// $$
392    /// but if $n < 0$, let
393    /// $$
394    /// -n - 1 = \sum_{i=0}^\infty 2^{1 - b_i},
395    /// $$
396    /// where for all $i$, $b_i\in \\{0, 1\\}$. Then
397    /// $$
398    /// n \gets \sum_{i=0}^\infty 2^{c_i},
399    /// $$
400    /// where
401    /// $$
402    /// \\{c_0, c_1, c_2, \ldots \\} =
403    /// \\{b_0, b_1, b_2, \ldots, b_{p-1}, d_0, d_1, \ldots, d_{p-q-1}, b_q, b_{q+1}, \ldots \\}.
404    /// $$
405    ///
406    /// # Worst-case complexity
407    /// $T(n) = O(n)$
408    ///
409    /// $M(m) = O(m)$
410    ///
411    /// where $T$ is time, $M$ is additional memory, $n$ is `max(self.significant_bits(), end)`, and
412    /// $m$ is `self.significant_bits()`.
413    ///
414    /// # Panics
415    /// Panics if `start > end`.
416    ///
417    /// # Examples
418    /// ```
419    /// use malachite_base::num::logic::traits::BitBlockAccess;
420    /// use malachite_nz::integer::Integer;
421    /// use malachite_nz::natural::Natural;
422    ///
423    /// let mut n = Integer::from(123);
424    /// n.assign_bits(5, 7, &Natural::from(456u32));
425    /// assert_eq!(n.to_string(), "27");
426    ///
427    /// let mut n = Integer::from(-123);
428    /// n.assign_bits(64, 128, &Natural::from(456u32));
429    /// assert_eq!(n.to_string(), "-340282366920938455033212565746503123067");
430    ///
431    /// let mut n = Integer::from(-123);
432    /// n.assign_bits(80, 100, &Natural::from(456u32));
433    /// assert_eq!(n.to_string(), "-1267098121128665515963862483067");
434    /// ```
435    fn assign_bits(&mut self, start: u64, end: u64, bits: &Natural) {
436        if self.sign {
437            self.abs.assign_bits(start, end, bits);
438        } else {
439            self.abs.neg_assign_bits(start, end, bits);
440        }
441    }
442}