Skip to main content

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