Skip to main content

twibint/biguint/
mod.rs

1//! biguint: declares the BigUint type and implements all its operations.
2
3use crate::traits::Digit;
4
5use core::cmp::Ordering;
6
7pub(crate) mod fmt;
8pub(crate) mod froms;
9pub(crate) mod ops;
10
11mod digits_vec;
12use digits_vec::Digits;
13
14#[cfg(test)]
15mod test;
16
17// TODO: implement ilog2 and that sort of things
18
19/// Representation of an unsigned integer with an infinite number of bits (above
20/// a certain position, they are all 0).
21///
22/// The internal representation is a Vec of a type that implements Digit as a radix representation.
23/// For zero, we cheat a little and use a vector with a single element: 0.
24#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct BigUint<T: Digit> {
26    pub(crate) val: Vec<T>,
27}
28
29impl<T: Digit> BigUint<T> {
30    /// Trivial constructor: from a single digit \
31    /// Integers higher than `T::MAX` are supposed to be constructed using the
32    /// various `From<_>` implementations.
33    pub fn new(val: T) -> BigUint<T> {
34        BigUint { val: vec![val] }
35    }
36
37    /// Allocates for at least `capacity` bits, total.
38    ///
39    /// ```
40    /// use twibint::BigUint;
41    /// let n = BigUint::<u64>::default().with_capacity(100);
42    /// assert!(n.capacity() >= 100);
43    /// ```
44    #[inline]
45    pub fn with_capacity(mut self, capacity: usize) -> BigUint<T> {
46        self.set_capacity(capacity);
47        self
48    }
49
50    /// Allocates for at least `capacity` bits, total.
51    ///
52    /// ```
53    /// use twibint::BigUint;
54    /// let mut n = BigUint::<u64>::default();
55    /// n.set_capacity(100);
56    /// assert!(n.capacity() >= 100);
57    /// ```
58    #[inline]
59    pub fn set_capacity(&mut self, capacity: usize) {
60        if capacity > 0 {
61            let target_length = (capacity - 1) / T::NB_BITS + 1;
62            let reserve = target_length.max(self.val.len()) - self.val.len();
63            self.val.reserve(reserve);
64        }
65    }
66
67    /// Returns the number of bits this integer can store without reallocating
68    ///
69    /// ```
70    /// use twibint::BigUint;
71    /// let n = BigUint::<u64>::default().with_capacity(100);
72    /// assert!(n.capacity() >= 100);
73    /// ```
74    #[inline]
75    pub fn capacity(&self) -> usize {
76        self.val.capacity() * T::NB_BITS
77    }
78
79    /// Returns the minimal number of bits necessary for a binary representation.
80    #[inline]
81    pub fn nb_bits(&self) -> usize {
82        nb_bits(&self.val)
83    }
84
85    /// Returns the bth bit as a bool. Since we represent an infinite number of bits,
86    /// b could be higher than `self.nb_bits()`
87    /// (but realistically to be other than 0 it will fit in a usize)
88    #[inline]
89    pub fn bit(&self, b: usize) -> bool {
90        if b >= self.val.len() * T::NB_BITS {
91            false
92        } else {
93            (self.val[b / T::NB_BITS] >> b % T::NB_BITS) & T::ONE != T::ZERO
94        }
95    }
96
97    /// Sets the bth bit of the integer. Since we represent an infinite number of bits,
98    /// b could be higher than `self.nb_bits()`
99    /// (but realistically to be other than 0 it will fit in a usize)
100    #[inline]
101    pub fn set_bit(&mut self, b: usize, val: bool) {
102        if val {
103            self.val
104                .resize((b / T::NB_BITS + 1).max(self.val.len()), T::ZERO);
105            let mask = T::ONE << (b % T::NB_BITS);
106            self.val[b / T::NB_BITS] |= mask;
107        } else {
108            let mask = T::MAX - (T::ONE << (b % T::NB_BITS));
109            self.val[b / T::NB_BITS] &= mask;
110            self.remove_leading_zeros();
111        }
112    }
113
114    /// Return an iterator on the bits, returning `bool` values. The iterator will
115    /// stop as soon as all the infinitely remaining bits are 0
116    #[inline]
117    pub fn bits(&self) -> impl DoubleEndedIterator<Item = bool> + '_ {
118        (0..self.nb_bits()).map(|b| self.bit(b))
119    }
120
121    /// Copies data from other into self, keeping self's allocation if possible
122    pub fn copy_from(&mut self, other: &Self) {
123        self.val.resize(other.val.len(), T::ZERO);
124        self.val[..].copy_from_slice(&other.val[..]);
125    }
126
127    /// (private) clean trailing zeros of the representation, if any, after an
128    /// operation has been performed.
129    #[inline]
130    pub(crate) fn remove_leading_zeros(&mut self) {
131        let count = self.val.len() - self.val.iter().rev().take_while(|n| **n == T::ZERO).count();
132        self.val.truncate(std::cmp::max(count, 1));
133    }
134
135    #[inline]
136    pub(crate) fn ord(&self, other: &[T]) -> Ordering {
137        ord(&self.val, other)
138    }
139}
140
141#[inline]
142pub(crate) fn nb_bits<T: Digit>(a: &[T]) -> usize {
143    match a.last() {
144        None => 0,
145        Some(last) => T::NB_BITS * (a.len() - 1) + (T::NB_BITS - last.leading_zeros() as usize),
146    }
147}
148
149#[inline]
150pub(crate) fn ord<T: Digit>(a: &[T], b: &[T]) -> Ordering {
151    let mut a_len = a.len();
152    while a_len > 0 && a[a_len - 1] == T::ZERO {
153        a_len -= 1;
154    }
155    let mut b_len = b.len();
156    while b_len > 0 && b[b_len - 1] == T::ZERO {
157        b_len -= 1;
158    }
159
160    match a_len.cmp(&b_len) {
161        Ordering::Equal => (),
162        o => return o,
163    };
164    for (a, b) in a[..a_len].iter().zip(b[..b_len].iter()).rev() {
165        match a.cmp(b) {
166            Ordering::Equal => continue,
167            o => return o,
168        };
169    }
170    Ordering::Equal
171}
172
173/// Default implementation for BigUint: returns 0.
174impl<T: Digit> Default for BigUint<T> {
175    fn default() -> BigUint<T> {
176        BigUint::new(T::ZERO)
177    }
178}
179
180impl<T: Digit> std::hash::Hash for BigUint<T> {
181    fn hash<H>(&self, state: &mut H)
182    where
183        H: std::hash::Hasher,
184    {
185        self.val.hash(state);
186    }
187}
188
189impl<T: Digit> PartialOrd<BigUint<T>> for BigUint<T> {
190    fn partial_cmp(&self, other: &BigUint<T>) -> Option<Ordering> {
191        Some(self.cmp(other))
192    }
193}
194
195impl<T: Digit> Ord for BigUint<T> {
196    fn cmp(&self, other: &BigUint<T>) -> Ordering {
197        self.ord(&other.val)
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use crate::biguint::ord;
204    use crate::traits::Digit;
205    use core::cmp::Ordering;
206
207    use typed_test_gen::test_with;
208
209    #[test_with(u32, u64)]
210    fn test_ord<T: Digit>() {
211        let a = [T::ONE, T::ONE, T::ZERO, T::ZERO];
212        let b = [T::ONE, T::ONE, T::ONE];
213        assert_eq!(ord(&a, &b), Ordering::Less);
214
215        let a = [T::ONE, T::ONE, T::ONE, T::ZERO];
216        let b = [T::ONE, T::ONE, T::ONE];
217        assert_eq!(ord(&a, &b), Ordering::Equal);
218
219        let a = [T::ONE, T::ONE, T::ONE, T::ZERO];
220        let b = [T::ONE, T::ZERO, T::ONE];
221        assert_eq!(ord(&a, &b), Ordering::Greater);
222    }
223}