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.
1112// 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]
2122/// 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`.
26fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);
2728/// 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`.
30fn full_div_rem(self, other: Self, borrow: Self)
31 -> (Self /* quotient */, Self /* remainder */);
32}
3334macro_rules!impl_full_ops {
35 ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
36 $(
37impl FullOps for $ty {
38fn 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)`.
41let (lo, hi) = self.carrying_mul_add(other, other2, carry);
42 (hi, lo)
43 }
4445fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) {
46debug_assert!(borrow < other);
47// This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`.
48let lhs = ((borrow as $bigty) << <$ty>::BITS) | (self as $bigty);
49let rhs = other as $bigty;
50 ((lhs / rhs) as $ty, (lhs % rhs) as $ty)
51 }
52 }
53 )*
54 )
55}
5657impl FullOps for u8 {
fn full_mul_add(self, other: u8, other2: u8, carry: u8) -> (u8, u8) {
let (lo, hi) = self.carrying_mul_add(other, other2, carry);
(hi, lo)
}
fn full_div_rem(self, other: u8, borrow: u8) -> (u8, u8) {
if true {
if !(borrow < other) {
crate::panicking::panic("assertion failed: borrow < other")
};
};
let lhs = ((borrow as u16) << <u8>::BITS) | (self as u16);
let rhs = other as u16;
((lhs / rhs) as u8, (lhs % rhs) as u8)
}
}
impl FullOps for u16 {
fn full_mul_add(self, other: u16, other2: u16, carry: u16) -> (u16, u16) {
let (lo, hi) = self.carrying_mul_add(other, other2, carry);
(hi, lo)
}
fn full_div_rem(self, other: u16, borrow: u16) -> (u16, u16) {
if true {
if !(borrow < other) {
crate::panicking::panic("assertion failed: borrow < other")
};
};
let lhs = ((borrow as u32) << <u16>::BITS) | (self as u32);
let rhs = other as u32;
((lhs / rhs) as u16, (lhs % rhs) as u16)
}
}
impl FullOps for u32 {
fn full_mul_add(self, other: u32, other2: u32, carry: u32) -> (u32, u32) {
let (lo, hi) = self.carrying_mul_add(other, other2, carry);
(hi, lo)
}
fn full_div_rem(self, other: u32, borrow: u32) -> (u32, u32) {
if true {
if !(borrow < other) {
crate::panicking::panic("assertion failed: borrow < other")
};
};
let lhs = ((borrow as u64) << <u32>::BITS) | (self as u64);
let rhs = other as u64;
((lhs / rhs) as u32, (lhs % rhs) as u32)
}
}
impl FullOps for u64 {
fn full_mul_add(self, other: u64, other2: u64, carry: u64) -> (u64, u64) {
let (lo, hi) = self.carrying_mul_add(other, other2, carry);
(hi, lo)
}
fn full_div_rem(self, other: u64, borrow: u64) -> (u64, u64) {
if true {
if !(borrow < other) {
crate::panicking::panic("assertion failed: borrow < other")
};
};
let lhs = ((borrow as u128) << <u64>::BITS) | (self as u128);
let rhs = other as u128;
((lhs / rhs) as u64, (lhs % rhs) as u64)
}
}impl_full_ops! {
58u8: add(intrinsics::u8_add_with_overflow), mul/div(u16);
59u16: add(intrinsics::u16_add_with_overflow), mul/div(u32);
60u32: add(intrinsics::u32_add_with_overflow), mul/div(u64);
61u64: add(intrinsics::u64_add_with_overflow), mul/div(u128);
62}6364/// 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)];
6869macro_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.
80pub 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.
84size: 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.
87base: [$ty; $n],
88 }
8990impl $name {
91/// Makes a bignum from one digit.
92pub fn from_small(v: $ty) -> $name {
93let mut base = [0; $n];
94 base[0] = v;
95$name { size: 1, base }
96 }
9798/// Makes a bignum from `u64` value.
99pub fn from_u64(mut v: u64) -> $name {
100let mut base = [0; $n];
101let mut sz = 0;
102while 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 }
109110/// 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.
113pub fn digits(&self) -> &[$ty] {
114&self.base[..self.size]
115 }
116117/// Returns the `i`-th bit where bit 0 is the least significant one.
118 /// In other words, the bit with weight `2^i`.
119pub fn get_bit(&self, i: usize) -> u8 {
120let digitbits = <$ty>::BITS as usize;
121let d = i / digitbits;
122let b = i % digitbits;
123 ((self.base[d] >> b) & 1) as u8
124 }
125126/// Returns `true` if the bignum is zero.
127pub fn is_zero(&self) -> bool {
128self.digits().iter().all(|&v| v == 0)
129 }
130131/// Returns the number of bits necessary to represent this value. Note that zero
132 /// is considered to need 0 bits.
133pub fn bit_length(&self) -> usize {
134let digitbits = <$ty>::BITS as usize;
135let digits = self.digits();
136// Find the most significant non-zero digit.
137let msd = digits.iter().rposition(|&x| x != 0);
138match msd {
139Some(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 }
144145/// Adds `other` to itself and returns its own mutable reference.
146pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
147use crate::{cmp, iter};
148149let mut sz = cmp::max(self.size, other.size);
150let mut carry = false;
151for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
152let (v, c) = (*a).carrying_add(*b, carry);
153*a = v;
154 carry = c;
155 }
156if carry {
157self.base[sz] = 1;
158 sz += 1;
159 }
160self.size = sz;
161self
162}
163164pub fn add_small(&mut self, other: $ty) -> &mut $name {
165let (v, mut carry) = self.base[0].carrying_add(other, false);
166self.base[0] = v;
167let mut i = 1;
168while carry {
169let (v, c) = self.base[i].carrying_add(0, carry);
170self.base[i] = v;
171 carry = c;
172 i += 1;
173 }
174if i > self.size {
175self.size = i;
176 }
177self
178}
179180/// Subtracts `other` from itself and returns its own mutable reference.
181pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
182use crate::{cmp, iter};
183184let sz = cmp::max(self.size, other.size);
185let mut noborrow = true;
186for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
187let (v, c) = (*a).carrying_add(!*b, noborrow);
188*a = v;
189 noborrow = c;
190 }
191assert!(noborrow);
192self.size = sz;
193self
194}
195196/// Multiplies itself by a digit-sized `other` and returns its own
197 /// mutable reference.
198pub fn mul_small(&mut self, other: $ty) -> &mut $name {
199let mut sz = self.size;
200let mut carry = 0;
201for a in &mut self.base[..sz] {
202let (v, c) = (*a).carrying_mul(other, carry);
203*a = v;
204 carry = c;
205 }
206if carry > 0 {
207self.base[sz] = carry;
208 sz += 1;
209 }
210self.size = sz;
211self
212}
213214/// Multiplies itself by `2^bits` and returns its own mutable reference.
215pub fn mul_pow2(&mut self, bits: usize) -> &mut $name {
216let digitbits = <$ty>::BITS as usize;
217let digits = bits / digitbits;
218let bits = bits % digitbits;
219220assert!(digits < $n);
221debug_assert!(self.base[$n - digits..].iter().all(|&v| v == 0));
222debug_assert!(bits == 0 || (self.base[$n - digits - 1] >> (digitbits - bits)) == 0);
223224// shift by `digits * digitbits` bits
225for i in (0..self.size).rev() {
226self.base[i + digits] = self.base[i];
227 }
228for i in 0..digits {
229self.base[i] = 0;
230 }
231232// shift by `bits` bits
233let mut sz = self.size + digits;
234if bits > 0 {
235let last = sz;
236let overflow = self.base[last - 1] >> (digitbits - bits);
237if overflow > 0 {
238self.base[last] = overflow;
239 sz += 1;
240 }
241for i in (digits + 1..last).rev() {
242self.base[i] =
243 (self.base[i] << bits) | (self.base[i - 1] >> (digitbits - bits));
244 }
245self.base[digits] <<= bits;
246// self.base[..digits] is zero, no need to shift
247}
248249self.size = sz;
250self
251}
252253/// Multiplies itself by `5^e` and returns its own mutable reference.
254pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name {
255use crate::num::imp::bignum::SMALL_POW5;
256257// 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.
259let table_index = size_of::<$ty>().trailing_zeros() as usize;
260let (small_power, small_e) = SMALL_POW5[table_index];
261let small_power = small_power as $ty;
262263// Multiply with the largest single-digit power as long as possible ...
264while e >= small_e {
265self.mul_small(small_power);
266 e -= small_e;
267 }
268269// ... then finish off the remainder.
270let mut rest_power = 1;
271for _ in 0..e {
272 rest_power *= 5;
273 }
274self.mul_small(rest_power);
275276self
277}
278279/// 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.
282pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name {
283// the internal routine. works best when aa.len() <= bb.len().
284fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize {
285use crate::num::imp::bignum::FullOps;
286287let mut retsz = 0;
288for (i, &a) in aa.iter().enumerate() {
289if a == 0 {
290continue;
291 }
292let mut sz = bb.len();
293let mut carry = 0;
294for (j, &b) in bb.iter().enumerate() {
295let (c, v) = a.full_mul_add(b, ret[i + j], carry);
296 ret[i + j] = v;
297 carry = c;
298 }
299if carry > 0 {
300 ret[i + sz] = carry;
301 sz += 1;
302 }
303if retsz < i + sz {
304 retsz = i + sz;
305 }
306 }
307 retsz
308 }
309310let mut ret = [0; $n];
311let 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 };
316self.base = ret;
317self.size = retsz;
318self
319}
320321/// Divides itself by a digit-sized `other` and returns its own
322 /// mutable reference *and* the remainder.
323pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) {
324use crate::num::imp::bignum::FullOps;
325326assert!(other > 0);
327328let sz = self.size;
329let mut borrow = 0;
330for a in self.base[..sz].iter_mut().rev() {
331let (q, r) = (*a).full_div_rem(other, borrow);
332*a = q;
333 borrow = r;
334 }
335 (self, borrow)
336 }
337 }
338339impl crate::cmp::PartialEq for $name {
340fn eq(&self, other: &$name) -> bool {
341self.base[..] == other.base[..]
342 }
343 }
344345impl crate::cmp::Eq for $name {}
346347impl crate::cmp::PartialOrd for $name {
348fn partial_cmp(&self, other: &$name) -> crate::option::Option<crate::cmp::Ordering> {
349crate::option::Option::Some(self.cmp(other))
350 }
351 }
352353impl crate::cmp::Ord for $name {
354fn cmp(&self, other: &$name) -> crate::cmp::Ordering {
355use crate::cmp::max;
356let sz = max(self.size, other.size);
357let lhs = self.base[..sz].iter().cloned().rev();
358let rhs = other.base[..sz].iter().cloned().rev();
359 lhs.cmp(rhs)
360 }
361 }
362363impl crate::clone::Clone for $name {
364fn clone(&self) -> Self {
365Self { size: self.size, base: self.base }
366 }
367 }
368369impl crate::clone::UseCloned for $name {}
370371impl crate::fmt::Debug for $name {
372fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
373let sz = if self.size < 1 { 1 } else { self.size };
374let digitlen = <$ty>::BITS as usize / 4;
375376write!(f, "{:#x}", self.base[sz - 1])?;
377for &v in self.base[..sz - 1].iter().rev() {
378write!(f, "_{:01$x}", v, digitlen)?;
379 }
380crate::result::Result::Ok(())
381 }
382 }
383 };
384}
385386/// the digit type for `Big32x40`
387pub type Digit32 = u32;
388389#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
390define_bignum!(Big32x40: type=Digit32, n=40);
391392/// The digit type for `Big64x20`.
393pub type Digit64 = u64;
394395#[cfg(target_pointer_width = "64")]
396/// Stack-allocated arbitrary-precision (up to certain limit) integer.
///
/// This is backed by a fixed-size array of given type ("digit").
/// While the array is not very large (normally some hundred bytes),
/// copying it recklessly may result in the performance hit.
/// Thus this is intentionally not `Copy`.
///
/// All operations available to bignums panic in the case of overflows.
/// The caller is responsible to use large enough bignum types.
pub struct Big64x20 {
/// One plus the offset to the maximum "digit" in use.
/// This does not decrease, so be aware of the computation order.
/// `base[size..]` should be zero.
size: usize,
/// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...`
/// where `W` is the number of bits in the digit type.
base: [Digit64; 20],
}
impl Big64x20 {
/// Makes a bignum from one digit.
pub fn from_small(v: Digit64) -> Big64x20 {
let mut base = [0; 20];
base[0] = v;
Big64x20 { size: 1, base }
}
/// Makes a bignum from `u64` value.
pub fn from_u64(mut v: u64) -> Big64x20 {
let mut base = [0; 20];
let mut sz = 0;
while v > 0 {
base[sz] = v as Digit64;
v = v.unbounded_shr(<Digit64>::BITS);
sz += 1;
}
Big64x20 { size: sz, base }
}
/// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric
/// value is `a + b * 2^W + c * 2^(2W) + ...` where `W` is the number of bits in
/// the digit type.
pub fn digits(&self) -> &[Digit64] { &self.base[..self.size] }
/// Returns the `i`-th bit where bit 0 is the least significant one.
/// In other words, the bit with weight `2^i`.
pub fn get_bit(&self, i: usize) -> u8 {
let digitbits = <Digit64>::BITS as usize;
let d = i / digitbits;
let b = i % digitbits;
((self.base[d] >> b) & 1) as u8
}
/// Returns `true` if the bignum is zero.
pub fn is_zero(&self) -> bool { self.digits().iter().all(|&v| v == 0) }
/// Returns the number of bits necessary to represent this value. Note that zero
/// is considered to need 0 bits.
pub fn bit_length(&self) -> usize {
let digitbits = <Digit64>::BITS as usize;
let digits = self.digits();
let msd = digits.iter().rposition(|&x| x != 0);
match msd {
Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
_ => 0,
}
}
/// Adds `other` to itself and returns its own mutable reference.
pub fn add<'a>(&'a mut self, other: &Big64x20) -> &'a mut Big64x20 {
use crate::{cmp, iter};
let mut sz = cmp::max(self.size, other.size);
let mut carry = false;
for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
let (v, c) = (*a).carrying_add(*b, carry);
*a = v;
carry = c;
}
if carry { self.base[sz] = 1; sz += 1; }
self.size = sz;
self
}
pub fn add_small(&mut self, other: Digit64) -> &mut Big64x20 {
let (v, mut carry) = self.base[0].carrying_add(other, false);
self.base[0] = v;
let mut i = 1;
while carry {
let (v, c) = self.base[i].carrying_add(0, carry);
self.base[i] = v;
carry = c;
i += 1;
}
if i > self.size { self.size = i; }
self
}
/// Subtracts `other` from itself and returns its own mutable reference.
pub fn sub<'a>(&'a mut self, other: &Big64x20) -> &'a mut Big64x20 {
use crate::{cmp, iter};
let sz = cmp::max(self.size, other.size);
let mut noborrow = true;
for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
let (v, c) = (*a).carrying_add(!*b, noborrow);
*a = v;
noborrow = c;
}
if !noborrow {
crate::panicking::panic("assertion failed: noborrow")
};
self.size = sz;
self
}
/// Multiplies itself by a digit-sized `other` and returns its own
/// mutable reference.
pub fn mul_small(&mut self, other: Digit64) -> &mut Big64x20 {
let mut sz = self.size;
let mut carry = 0;
for a in &mut self.base[..sz] {
let (v, c) = (*a).carrying_mul(other, carry);
*a = v;
carry = c;
}
if carry > 0 { self.base[sz] = carry; sz += 1; }
self.size = sz;
self
}
/// Multiplies itself by `2^bits` and returns its own mutable reference.
pub fn mul_pow2(&mut self, bits: usize) -> &mut Big64x20 {
let digitbits = <Digit64>::BITS as usize;
let digits = bits / digitbits;
let bits = bits % digitbits;
if !(digits < 20) {
crate::panicking::panic("assertion failed: digits < 20")
};
if true {
if !self.base[20 - digits..].iter().all(|&v| v == 0) {
crate::panicking::panic("assertion failed: self.base[20 - digits..].iter().all(|&v| v == 0)")
};
};
if true {
if !(bits == 0 ||
(self.base[20 - digits - 1] >> (digitbits - bits)) == 0) {
crate::panicking::panic("assertion failed: bits == 0 || (self.base[20 - digits - 1] >> (digitbits - bits)) == 0")
};
};
for i in (0..self.size).rev() {
self.base[i + digits] = self.base[i];
}
for i in 0..digits { self.base[i] = 0; }
let mut sz = self.size + digits;
if bits > 0 {
let last = sz;
let overflow = self.base[last - 1] >> (digitbits - bits);
if overflow > 0 { self.base[last] = overflow; sz += 1; }
for i in (digits + 1..last).rev() {
self.base[i] =
(self.base[i] << bits) |
(self.base[i - 1] >> (digitbits - bits));
}
self.base[digits] <<= bits;
}
self.size = sz;
self
}
/// Multiplies itself by `5^e` and returns its own mutable reference.
pub fn mul_pow5(&mut self, mut e: usize) -> &mut Big64x20 {
use crate::num::imp::bignum::SMALL_POW5;
let table_index = size_of::<Digit64>().trailing_zeros() as usize;
let (small_power, small_e) = SMALL_POW5[table_index];
let small_power = small_power as Digit64;
while e >= small_e { self.mul_small(small_power); e -= small_e; }
let mut rest_power = 1;
for _ in 0..e { rest_power *= 5; }
self.mul_small(rest_power);
self
}
/// Multiplies itself by a number described by `other[0] + other[1] * 2^W +
/// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type)
/// and returns its own mutable reference.
pub fn mul_digits<'a>(&'a mut self, other: &[Digit64])
-> &'a mut Big64x20 {
fn mul_inner(ret: &mut [Digit64; 20], aa: &[Digit64], bb: &[Digit64])
-> usize {
use crate::num::imp::bignum::FullOps;
let mut retsz = 0;
for (i, &a) in aa.iter().enumerate() {
if a == 0 { continue; }
let mut sz = bb.len();
let mut carry = 0;
for (j, &b) in bb.iter().enumerate() {
let (c, v) = a.full_mul_add(b, ret[i + j], carry);
ret[i + j] = v;
carry = c;
}
if carry > 0 { ret[i + sz] = carry; sz += 1; }
if retsz < i + sz { retsz = i + sz; }
}
retsz
}
let mut ret = [0; 20];
let retsz =
if self.size < other.len() {
mul_inner(&mut ret, &self.digits(), other)
} else { mul_inner(&mut ret, other, &self.digits()) };
self.base = ret;
self.size = retsz;
self
}
/// Divides itself by a digit-sized `other` and returns its own
/// mutable reference *and* the remainder.
pub fn div_rem_small(&mut self, other: Digit64)
-> (&mut Big64x20, Digit64) {
use crate::num::imp::bignum::FullOps;
if !(other > 0) {
crate::panicking::panic("assertion failed: other > 0")
};
let sz = self.size;
let mut borrow = 0;
for a in self.base[..sz].iter_mut().rev() {
let (q, r) = (*a).full_div_rem(other, borrow);
*a = q;
borrow = r;
}
(self, borrow)
}
}
impl crate::cmp::PartialEq for Big64x20 {
fn eq(&self, other: &Big64x20) -> bool { self.base[..] == other.base[..] }
}
impl crate::cmp::Eq for Big64x20 {}
impl crate::cmp::PartialOrd for Big64x20 {
fn partial_cmp(&self, other: &Big64x20)
-> crate::option::Option<crate::cmp::Ordering> {
crate::option::Option::Some(self.cmp(other))
}
}
impl crate::cmp::Ord for Big64x20 {
fn cmp(&self, other: &Big64x20) -> crate::cmp::Ordering {
use crate::cmp::max;
let sz = max(self.size, other.size);
let lhs = self.base[..sz].iter().cloned().rev();
let rhs = other.base[..sz].iter().cloned().rev();
lhs.cmp(rhs)
}
}
impl crate::clone::Clone for Big64x20 {
fn clone(&self) -> Self { Self { size: self.size, base: self.base } }
}
impl crate::clone::UseCloned for Big64x20 {}
impl crate::fmt::Debug for Big64x20 {
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
let sz = if self.size < 1 { 1 } else { self.size };
let digitlen = <Digit64>::BITS as usize / 4;
f.write_fmt(format_args!("{0:#x}", self.base[sz - 1]))?;
for &v in self.base[..sz - 1].iter().rev() {
f.write_fmt(format_args!("_{0:01$x}", v, digitlen))?;
}
crate::result::Result::Ok(())
}
}define_bignum!(Big64x20: type=Digit64, n=20);
397398#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
399pub type Big = Big32x40;
400#[cfg(target_pointer_width = "64")]
401pub type Big = Big64x20;
402403#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
404pub type Digit = Digit32;
405#[cfg(target_pointer_width = "64")]
406pub type Digit = Digit64;
407408// this one is used for testing only.
409#[doc(hidden)]
410pub mod tests {
411/// Stack-allocated arbitrary-precision (up to certain limit) integer.
///
/// This is backed by a fixed-size array of given type ("digit").
/// While the array is not very large (normally some hundred bytes),
/// copying it recklessly may result in the performance hit.
/// Thus this is intentionally not `Copy`.
///
/// All operations available to bignums panic in the case of overflows.
/// The caller is responsible to use large enough bignum types.
pub struct Big8x3 {
/// One plus the offset to the maximum "digit" in use.
/// This does not decrease, so be aware of the computation order.
/// `base[size..]` should be zero.
size: usize,
/// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...`
/// where `W` is the number of bits in the digit type.
base: [u8; 3],
}
impl Big8x3 {
/// Makes a bignum from one digit.
pub fn from_small(v: u8) -> Big8x3 {
let mut base = [0; 3];
base[0] = v;
Big8x3 { size: 1, base }
}
/// Makes a bignum from `u64` value.
pub fn from_u64(mut v: u64) -> Big8x3 {
let mut base = [0; 3];
let mut sz = 0;
while v > 0 {
base[sz] = v as u8;
v = v.unbounded_shr(<u8>::BITS);
sz += 1;
}
Big8x3 { size: sz, base }
}
/// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric
/// value is `a + b * 2^W + c * 2^(2W) + ...` where `W` is the number of bits in
/// the digit type.
pub fn digits(&self) -> &[u8] { &self.base[..self.size] }
/// Returns the `i`-th bit where bit 0 is the least significant one.
/// In other words, the bit with weight `2^i`.
pub fn get_bit(&self, i: usize) -> u8 {
let digitbits = <u8>::BITS as usize;
let d = i / digitbits;
let b = i % digitbits;
((self.base[d] >> b) & 1) as u8
}
/// Returns `true` if the bignum is zero.
pub fn is_zero(&self) -> bool { self.digits().iter().all(|&v| v == 0) }
/// Returns the number of bits necessary to represent this value. Note that zero
/// is considered to need 0 bits.
pub fn bit_length(&self) -> usize {
let digitbits = <u8>::BITS as usize;
let digits = self.digits();
let msd = digits.iter().rposition(|&x| x != 0);
match msd {
Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
_ => 0,
}
}
/// Adds `other` to itself and returns its own mutable reference.
pub fn add<'a>(&'a mut self, other: &Big8x3) -> &'a mut Big8x3 {
use crate::{cmp, iter};
let mut sz = cmp::max(self.size, other.size);
let mut carry = false;
for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
let (v, c) = (*a).carrying_add(*b, carry);
*a = v;
carry = c;
}
if carry { self.base[sz] = 1; sz += 1; }
self.size = sz;
self
}
pub fn add_small(&mut self, other: u8) -> &mut Big8x3 {
let (v, mut carry) = self.base[0].carrying_add(other, false);
self.base[0] = v;
let mut i = 1;
while carry {
let (v, c) = self.base[i].carrying_add(0, carry);
self.base[i] = v;
carry = c;
i += 1;
}
if i > self.size { self.size = i; }
self
}
/// Subtracts `other` from itself and returns its own mutable reference.
pub fn sub<'a>(&'a mut self, other: &Big8x3) -> &'a mut Big8x3 {
use crate::{cmp, iter};
let sz = cmp::max(self.size, other.size);
let mut noborrow = true;
for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
let (v, c) = (*a).carrying_add(!*b, noborrow);
*a = v;
noborrow = c;
}
if !noborrow {
crate::panicking::panic("assertion failed: noborrow")
};
self.size = sz;
self
}
/// Multiplies itself by a digit-sized `other` and returns its own
/// mutable reference.
pub fn mul_small(&mut self, other: u8) -> &mut Big8x3 {
let mut sz = self.size;
let mut carry = 0;
for a in &mut self.base[..sz] {
let (v, c) = (*a).carrying_mul(other, carry);
*a = v;
carry = c;
}
if carry > 0 { self.base[sz] = carry; sz += 1; }
self.size = sz;
self
}
/// Multiplies itself by `2^bits` and returns its own mutable reference.
pub fn mul_pow2(&mut self, bits: usize) -> &mut Big8x3 {
let digitbits = <u8>::BITS as usize;
let digits = bits / digitbits;
let bits = bits % digitbits;
if !(digits < 3) {
crate::panicking::panic("assertion failed: digits < 3")
};
if true {
if !self.base[3 - digits..].iter().all(|&v| v == 0) {
crate::panicking::panic("assertion failed: self.base[3 - digits..].iter().all(|&v| v == 0)")
};
};
if true {
if !(bits == 0 ||
(self.base[3 - digits - 1] >> (digitbits - bits)) == 0) {
crate::panicking::panic("assertion failed: bits == 0 || (self.base[3 - digits - 1] >> (digitbits - bits)) == 0")
};
};
for i in (0..self.size).rev() {
self.base[i + digits] = self.base[i];
}
for i in 0..digits { self.base[i] = 0; }
let mut sz = self.size + digits;
if bits > 0 {
let last = sz;
let overflow = self.base[last - 1] >> (digitbits - bits);
if overflow > 0 { self.base[last] = overflow; sz += 1; }
for i in (digits + 1..last).rev() {
self.base[i] =
(self.base[i] << bits) |
(self.base[i - 1] >> (digitbits - bits));
}
self.base[digits] <<= bits;
}
self.size = sz;
self
}
/// Multiplies itself by `5^e` and returns its own mutable reference.
pub fn mul_pow5(&mut self, mut e: usize) -> &mut Big8x3 {
use crate::num::imp::bignum::SMALL_POW5;
let table_index = size_of::<u8>().trailing_zeros() as usize;
let (small_power, small_e) = SMALL_POW5[table_index];
let small_power = small_power as u8;
while e >= small_e { self.mul_small(small_power); e -= small_e; }
let mut rest_power = 1;
for _ in 0..e { rest_power *= 5; }
self.mul_small(rest_power);
self
}
/// Multiplies itself by a number described by `other[0] + other[1] * 2^W +
/// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type)
/// and returns its own mutable reference.
pub fn mul_digits<'a>(&'a mut self, other: &[u8]) -> &'a mut Big8x3 {
fn mul_inner(ret: &mut [u8; 3], aa: &[u8], bb: &[u8]) -> usize {
use crate::num::imp::bignum::FullOps;
let mut retsz = 0;
for (i, &a) in aa.iter().enumerate() {
if a == 0 { continue; }
let mut sz = bb.len();
let mut carry = 0;
for (j, &b) in bb.iter().enumerate() {
let (c, v) = a.full_mul_add(b, ret[i + j], carry);
ret[i + j] = v;
carry = c;
}
if carry > 0 { ret[i + sz] = carry; sz += 1; }
if retsz < i + sz { retsz = i + sz; }
}
retsz
}
let mut ret = [0; 3];
let retsz =
if self.size < other.len() {
mul_inner(&mut ret, &self.digits(), other)
} else { mul_inner(&mut ret, other, &self.digits()) };
self.base = ret;
self.size = retsz;
self
}
/// Divides itself by a digit-sized `other` and returns its own
/// mutable reference *and* the remainder.
pub fn div_rem_small(&mut self, other: u8) -> (&mut Big8x3, u8) {
use crate::num::imp::bignum::FullOps;
if !(other > 0) {
crate::panicking::panic("assertion failed: other > 0")
};
let sz = self.size;
let mut borrow = 0;
for a in self.base[..sz].iter_mut().rev() {
let (q, r) = (*a).full_div_rem(other, borrow);
*a = q;
borrow = r;
}
(self, borrow)
}
}
impl crate::cmp::PartialEq for Big8x3 {
fn eq(&self, other: &Big8x3) -> bool { self.base[..] == other.base[..] }
}
impl crate::cmp::Eq for Big8x3 {}
impl crate::cmp::PartialOrd for Big8x3 {
fn partial_cmp(&self, other: &Big8x3)
-> crate::option::Option<crate::cmp::Ordering> {
crate::option::Option::Some(self.cmp(other))
}
}
impl crate::cmp::Ord for Big8x3 {
fn cmp(&self, other: &Big8x3) -> crate::cmp::Ordering {
use crate::cmp::max;
let sz = max(self.size, other.size);
let lhs = self.base[..sz].iter().cloned().rev();
let rhs = other.base[..sz].iter().cloned().rev();
lhs.cmp(rhs)
}
}
impl crate::clone::Clone for Big8x3 {
fn clone(&self) -> Self { Self { size: self.size, base: self.base } }
}
impl crate::clone::UseCloned for Big8x3 {}
impl crate::fmt::Debug for Big8x3 {
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
let sz = if self.size < 1 { 1 } else { self.size };
let digitlen = <u8>::BITS as usize / 4;
f.write_fmt(format_args!("{0:#x}", self.base[sz - 1]))?;
for &v in self.base[..sz - 1].iter().rev() {
f.write_fmt(format_args!("_{0:01$x}", v, digitlen))?;
}
crate::result::Result::Ok(())
}
}define_bignum!(Big8x3: type=u8, n=3);
412}