core/num/
bignum.rs

1//! Custom arbitrary-precision number (bignum) implementation.
2//!
3//! This is designed to avoid the heap allocation at expense of stack memory.
4//! The most used bignum type, `Big32x40`, is limited by 32 × 40 = 1,280 bits
5//! and will take at most 160 bytes of stack memory. This is more than enough
6//! for round-tripping all possible finite `f64` values.
7//!
8//! In principle it is possible to have multiple bignum types for different
9//! inputs, but we don't do so to avoid the code bloat. Each bignum is still
10//! tracked for the actual usages, so it normally doesn't matter.
11
12// This module is only for dec2flt and flt2dec, and only public because of coretests.
13// It is not intended to ever be stabilized.
14#![doc(hidden)]
15#![unstable(
16    feature = "core_private_bignum",
17    reason = "internal routines only exposed for testing",
18    issue = "none"
19)]
20#![macro_use]
21
22/// Arithmetic operations required by bignums.
23pub trait FullOps: Sized {
24    /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
25    /// where `W` is the number of bits in `Self`.
26    fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);
27
28    /// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem`
29    /// and `0 <= rem < other`, where `W` is the number of bits in `Self`.
30    fn full_div_rem(self, other: Self, borrow: Self)
31    -> (Self /* quotient */, Self /* remainder */);
32}
33
34macro_rules! impl_full_ops {
35    ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
36        $(
37            impl FullOps for $ty {
38                fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
39                    // This cannot overflow;
40                    // the output is between `0` and `2^nbits * (2^nbits - 1)`.
41                    let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) +
42                            (carry as $bigty);
43                    ((v >> <$ty>::BITS) as $ty, v as $ty)
44                }
45
46                fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) {
47                    debug_assert!(borrow < other);
48                    // This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`.
49                    let lhs = ((borrow as $bigty) << <$ty>::BITS) | (self as $bigty);
50                    let rhs = other as $bigty;
51                    ((lhs / rhs) as $ty, (lhs % rhs) as $ty)
52                }
53            }
54        )*
55    )
56}
57
58impl_full_ops! {
59    u8:  add(intrinsics::u8_add_with_overflow),  mul/div(u16);
60    u16: add(intrinsics::u16_add_with_overflow), mul/div(u32);
61    u32: add(intrinsics::u32_add_with_overflow), mul/div(u64);
62    // See RFC #521 for enabling this.
63    // u64: add(intrinsics::u64_add_with_overflow), mul/div(u128);
64}
65
66/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value
67/// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`.
68const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)];
69
70macro_rules! define_bignum {
71    ($name:ident: type=$ty:ty, n=$n:expr) => {
72        /// Stack-allocated arbitrary-precision (up to certain limit) integer.
73        ///
74        /// This is backed by a fixed-size array of given type ("digit").
75        /// While the array is not very large (normally some hundred bytes),
76        /// copying it recklessly may result in the performance hit.
77        /// Thus this is intentionally not `Copy`.
78        ///
79        /// All operations available to bignums panic in the case of overflows.
80        /// The caller is responsible to use large enough bignum types.
81        pub struct $name {
82            /// One plus the offset to the maximum "digit" in use.
83            /// This does not decrease, so be aware of the computation order.
84            /// `base[size..]` should be zero.
85            size: usize,
86            /// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...`
87            /// where `W` is the number of bits in the digit type.
88            base: [$ty; $n],
89        }
90
91        impl $name {
92            /// Makes a bignum from one digit.
93            pub fn from_small(v: $ty) -> $name {
94                let mut base = [0; $n];
95                base[0] = v;
96                $name { size: 1, base }
97            }
98
99            /// Makes a bignum from `u64` value.
100            pub fn from_u64(mut v: u64) -> $name {
101                let mut base = [0; $n];
102                let mut sz = 0;
103                while v > 0 {
104                    base[sz] = v as $ty;
105                    v >>= <$ty>::BITS;
106                    sz += 1;
107                }
108                $name { size: sz, base }
109            }
110
111            /// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric
112            /// value is `a + b * 2^W + c * 2^(2W) + ...` where `W` is the number of bits in
113            /// the digit type.
114            pub fn digits(&self) -> &[$ty] {
115                &self.base[..self.size]
116            }
117
118            /// Returns the `i`-th bit where bit 0 is the least significant one.
119            /// In other words, the bit with weight `2^i`.
120            pub fn get_bit(&self, i: usize) -> u8 {
121                let digitbits = <$ty>::BITS as usize;
122                let d = i / digitbits;
123                let b = i % digitbits;
124                ((self.base[d] >> b) & 1) as u8
125            }
126
127            /// Returns `true` if the bignum is zero.
128            pub fn is_zero(&self) -> bool {
129                self.digits().iter().all(|&v| v == 0)
130            }
131
132            /// Returns the number of bits necessary to represent this value. Note that zero
133            /// is considered to need 0 bits.
134            pub fn bit_length(&self) -> usize {
135                let digitbits = <$ty>::BITS as usize;
136                let digits = self.digits();
137                // Find the most significant non-zero digit.
138                let msd = digits.iter().rposition(|&x| x != 0);
139                match msd {
140                    Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
141                    // There are no non-zero digits, i.e., the number is zero.
142                    _ => 0,
143                }
144            }
145
146            /// Adds `other` to itself and returns its own mutable reference.
147            pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
148                use crate::{cmp, iter};
149
150                let mut sz = cmp::max(self.size, other.size);
151                let mut carry = false;
152                for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
153                    let (v, c) = (*a).carrying_add(*b, carry);
154                    *a = v;
155                    carry = c;
156                }
157                if carry {
158                    self.base[sz] = 1;
159                    sz += 1;
160                }
161                self.size = sz;
162                self
163            }
164
165            pub fn add_small(&mut self, other: $ty) -> &mut $name {
166                let (v, mut carry) = self.base[0].carrying_add(other, false);
167                self.base[0] = v;
168                let mut i = 1;
169                while carry {
170                    let (v, c) = self.base[i].carrying_add(0, carry);
171                    self.base[i] = v;
172                    carry = c;
173                    i += 1;
174                }
175                if i > self.size {
176                    self.size = i;
177                }
178                self
179            }
180
181            /// Subtracts `other` from itself and returns its own mutable reference.
182            pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
183                use crate::{cmp, iter};
184
185                let sz = cmp::max(self.size, other.size);
186                let mut noborrow = true;
187                for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
188                    let (v, c) = (*a).carrying_add(!*b, noborrow);
189                    *a = v;
190                    noborrow = c;
191                }
192                assert!(noborrow);
193                self.size = sz;
194                self
195            }
196
197            /// Multiplies itself by a digit-sized `other` and returns its own
198            /// mutable reference.
199            pub fn mul_small(&mut self, other: $ty) -> &mut $name {
200                let mut sz = self.size;
201                let mut carry = 0;
202                for a in &mut self.base[..sz] {
203                    let (v, c) = (*a).carrying_mul(other, carry);
204                    *a = v;
205                    carry = c;
206                }
207                if carry > 0 {
208                    self.base[sz] = carry;
209                    sz += 1;
210                }
211                self.size = sz;
212                self
213            }
214
215            /// Multiplies itself by `2^bits` and returns its own mutable reference.
216            pub fn mul_pow2(&mut self, bits: usize) -> &mut $name {
217                let digitbits = <$ty>::BITS as usize;
218                let digits = bits / digitbits;
219                let bits = bits % digitbits;
220
221                assert!(digits < $n);
222                debug_assert!(self.base[$n - digits..].iter().all(|&v| v == 0));
223                debug_assert!(bits == 0 || (self.base[$n - digits - 1] >> (digitbits - bits)) == 0);
224
225                // shift by `digits * digitbits` bits
226                for i in (0..self.size).rev() {
227                    self.base[i + digits] = self.base[i];
228                }
229                for i in 0..digits {
230                    self.base[i] = 0;
231                }
232
233                // shift by `bits` bits
234                let mut sz = self.size + digits;
235                if bits > 0 {
236                    let last = sz;
237                    let overflow = self.base[last - 1] >> (digitbits - bits);
238                    if overflow > 0 {
239                        self.base[last] = overflow;
240                        sz += 1;
241                    }
242                    for i in (digits + 1..last).rev() {
243                        self.base[i] =
244                            (self.base[i] << bits) | (self.base[i - 1] >> (digitbits - bits));
245                    }
246                    self.base[digits] <<= bits;
247                    // self.base[..digits] is zero, no need to shift
248                }
249
250                self.size = sz;
251                self
252            }
253
254            /// Multiplies itself by `5^e` and returns its own mutable reference.
255            pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name {
256                use crate::mem;
257                use crate::num::bignum::SMALL_POW5;
258
259                // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes
260                // are consecutive powers of two, so this is well suited index for the table.
261                let table_index = mem::size_of::<$ty>().trailing_zeros() as usize;
262                let (small_power, small_e) = SMALL_POW5[table_index];
263                let small_power = small_power as $ty;
264
265                // Multiply with the largest single-digit power as long as possible ...
266                while e >= small_e {
267                    self.mul_small(small_power);
268                    e -= small_e;
269                }
270
271                // ... then finish off the remainder.
272                let mut rest_power = 1;
273                for _ in 0..e {
274                    rest_power *= 5;
275                }
276                self.mul_small(rest_power);
277
278                self
279            }
280
281            /// Multiplies itself by a number described by `other[0] + other[1] * 2^W +
282            /// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type)
283            /// and returns its own mutable reference.
284            pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name {
285                // the internal routine. works best when aa.len() <= bb.len().
286                fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize {
287                    use crate::num::bignum::FullOps;
288
289                    let mut retsz = 0;
290                    for (i, &a) in aa.iter().enumerate() {
291                        if a == 0 {
292                            continue;
293                        }
294                        let mut sz = bb.len();
295                        let mut carry = 0;
296                        for (j, &b) in bb.iter().enumerate() {
297                            let (c, v) = a.full_mul_add(b, ret[i + j], carry);
298                            ret[i + j] = v;
299                            carry = c;
300                        }
301                        if carry > 0 {
302                            ret[i + sz] = carry;
303                            sz += 1;
304                        }
305                        if retsz < i + sz {
306                            retsz = i + sz;
307                        }
308                    }
309                    retsz
310                }
311
312                let mut ret = [0; $n];
313                let retsz = if self.size < other.len() {
314                    mul_inner(&mut ret, &self.digits(), other)
315                } else {
316                    mul_inner(&mut ret, other, &self.digits())
317                };
318                self.base = ret;
319                self.size = retsz;
320                self
321            }
322
323            /// Divides itself by a digit-sized `other` and returns its own
324            /// mutable reference *and* the remainder.
325            pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) {
326                use crate::num::bignum::FullOps;
327
328                assert!(other > 0);
329
330                let sz = self.size;
331                let mut borrow = 0;
332                for a in self.base[..sz].iter_mut().rev() {
333                    let (q, r) = (*a).full_div_rem(other, borrow);
334                    *a = q;
335                    borrow = r;
336                }
337                (self, borrow)
338            }
339
340            /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the
341            /// remainder.
342            pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) {
343                // Stupid slow base-2 long division taken from
344                // https://en.wikipedia.org/wiki/Division_algorithm
345                // FIXME use a greater base ($ty) for the long division.
346                assert!(!d.is_zero());
347                let digitbits = <$ty>::BITS as usize;
348                for digit in &mut q.base[..] {
349                    *digit = 0;
350                }
351                for digit in &mut r.base[..] {
352                    *digit = 0;
353                }
354                r.size = d.size;
355                q.size = 1;
356                let mut q_is_zero = true;
357                let end = self.bit_length();
358                for i in (0..end).rev() {
359                    r.mul_pow2(1);
360                    r.base[0] |= self.get_bit(i) as $ty;
361                    if &*r >= d {
362                        r.sub(d);
363                        // Set bit `i` of q to 1.
364                        let digit_idx = i / digitbits;
365                        let bit_idx = i % digitbits;
366                        if q_is_zero {
367                            q.size = digit_idx + 1;
368                            q_is_zero = false;
369                        }
370                        q.base[digit_idx] |= 1 << bit_idx;
371                    }
372                }
373                debug_assert!(q.base[q.size..].iter().all(|&d| d == 0));
374                debug_assert!(r.base[r.size..].iter().all(|&d| d == 0));
375            }
376        }
377
378        impl crate::cmp::PartialEq for $name {
379            fn eq(&self, other: &$name) -> bool {
380                self.base[..] == other.base[..]
381            }
382        }
383
384        impl crate::cmp::Eq for $name {}
385
386        impl crate::cmp::PartialOrd for $name {
387            fn partial_cmp(&self, other: &$name) -> crate::option::Option<crate::cmp::Ordering> {
388                crate::option::Option::Some(self.cmp(other))
389            }
390        }
391
392        impl crate::cmp::Ord for $name {
393            fn cmp(&self, other: &$name) -> crate::cmp::Ordering {
394                use crate::cmp::max;
395                let sz = max(self.size, other.size);
396                let lhs = self.base[..sz].iter().cloned().rev();
397                let rhs = other.base[..sz].iter().cloned().rev();
398                lhs.cmp(rhs)
399            }
400        }
401
402        impl crate::clone::Clone for $name {
403            fn clone(&self) -> Self {
404                Self { size: self.size, base: self.base }
405            }
406        }
407
408        impl crate::fmt::Debug for $name {
409            fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
410                let sz = if self.size < 1 { 1 } else { self.size };
411                let digitlen = <$ty>::BITS as usize / 4;
412
413                write!(f, "{:#x}", self.base[sz - 1])?;
414                for &v in self.base[..sz - 1].iter().rev() {
415                    write!(f, "_{:01$x}", v, digitlen)?;
416                }
417                crate::result::Result::Ok(())
418            }
419        }
420    };
421}
422
423/// The digit type for `Big32x40`.
424pub type Digit32 = u32;
425
426define_bignum!(Big32x40: type=Digit32, n=40);
427
428// this one is used for testing only.
429#[doc(hidden)]
430pub mod tests {
431    define_bignum!(Big8x3: type=u8, n=3);
432}