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.
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 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} value
65/// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`.
66const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)];
6768macro_rules!define_bignum {
69 ($name:ident: type=$ty:ty, n=$n:expr) => {
70/// Stack-allocated arbitrary-precision (up to certain limit) integer.
71 ///
72 /// This is backed by a fixed-size array of given type ("digit").
73 /// While the array is not very large (normally some hundred bytes),
74 /// copying it recklessly may result in the performance hit.
75 /// Thus this is intentionally not `Copy`.
76 ///
77 /// All operations available to bignums panic in the case of overflows.
78 /// The caller is responsible to use large enough bignum types.
79pub struct $name {
80/// One plus the offset to the maximum "digit" in use.
81 /// This does not decrease, so be aware of the computation order.
82 /// `base[size..]` should be zero.
83size: usize,
84/// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...`
85 /// where `W` is the number of bits in the digit type.
86base: [$ty; $n],
87 }
8889impl $name {
90/// Makes a bignum from one digit.
91pub fn from_small(v: $ty) -> $name {
92let mut base = [0; $n];
93 base[0] = v;
94$name { size: 1, base }
95 }
9697/// Makes a bignum from `u64` value.
98pub fn from_u64(mut v: u64) -> $name {
99let mut base = [0; $n];
100let mut sz = 0;
101while v > 0 {
102 base[sz] = v as $ty;
103 v >>= <$ty>::BITS;
104 sz += 1;
105 }
106$name { size: sz, base }
107 }
108109/// Returns the internal digits as a slice `[a, b, c, ...]` such that the numeric
110 /// value is `a + b * 2^W + c * 2^(2W) + ...` where `W` is the number of bits in
111 /// the digit type.
112pub fn digits(&self) -> &[$ty] {
113&self.base[..self.size]
114 }
115116/// Returns the `i`-th bit where bit 0 is the least significant one.
117 /// In other words, the bit with weight `2^i`.
118pub fn get_bit(&self, i: usize) -> u8 {
119let digitbits = <$ty>::BITS as usize;
120let d = i / digitbits;
121let b = i % digitbits;
122 ((self.base[d] >> b) & 1) as u8
123 }
124125/// Returns `true` if the bignum is zero.
126pub fn is_zero(&self) -> bool {
127self.digits().iter().all(|&v| v == 0)
128 }
129130/// Returns the number of bits necessary to represent this value. Note that zero
131 /// is considered to need 0 bits.
132pub fn bit_length(&self) -> usize {
133let digitbits = <$ty>::BITS as usize;
134let digits = self.digits();
135// Find the most significant non-zero digit.
136let msd = digits.iter().rposition(|&x| x != 0);
137match msd {
138Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
139// There are no non-zero digits, i.e., the number is zero.
140_ => 0,
141 }
142 }
143144/// Adds `other` to itself and returns its own mutable reference.
145pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
146use crate::{cmp, iter};
147148let mut sz = cmp::max(self.size, other.size);
149let mut carry = false;
150for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
151let (v, c) = (*a).carrying_add(*b, carry);
152*a = v;
153 carry = c;
154 }
155if carry {
156self.base[sz] = 1;
157 sz += 1;
158 }
159self.size = sz;
160self
161}
162163pub fn add_small(&mut self, other: $ty) -> &mut $name {
164let (v, mut carry) = self.base[0].carrying_add(other, false);
165self.base[0] = v;
166let mut i = 1;
167while carry {
168let (v, c) = self.base[i].carrying_add(0, carry);
169self.base[i] = v;
170 carry = c;
171 i += 1;
172 }
173if i > self.size {
174self.size = i;
175 }
176self
177}
178179/// Subtracts `other` from itself and returns its own mutable reference.
180pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
181use crate::{cmp, iter};
182183let sz = cmp::max(self.size, other.size);
184let mut noborrow = true;
185for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
186let (v, c) = (*a).carrying_add(!*b, noborrow);
187*a = v;
188 noborrow = c;
189 }
190assert!(noborrow);
191self.size = sz;
192self
193}
194195/// Multiplies itself by a digit-sized `other` and returns its own
196 /// mutable reference.
197pub fn mul_small(&mut self, other: $ty) -> &mut $name {
198let mut sz = self.size;
199let mut carry = 0;
200for a in &mut self.base[..sz] {
201let (v, c) = (*a).carrying_mul(other, carry);
202*a = v;
203 carry = c;
204 }
205if carry > 0 {
206self.base[sz] = carry;
207 sz += 1;
208 }
209self.size = sz;
210self
211}
212213/// Multiplies itself by `2^bits` and returns its own mutable reference.
214pub fn mul_pow2(&mut self, bits: usize) -> &mut $name {
215let digitbits = <$ty>::BITS as usize;
216let digits = bits / digitbits;
217let bits = bits % digitbits;
218219assert!(digits < $n);
220debug_assert!(self.base[$n - digits..].iter().all(|&v| v == 0));
221debug_assert!(bits == 0 || (self.base[$n - digits - 1] >> (digitbits - bits)) == 0);
222223// shift by `digits * digitbits` bits
224for i in (0..self.size).rev() {
225self.base[i + digits] = self.base[i];
226 }
227for i in 0..digits {
228self.base[i] = 0;
229 }
230231// shift by `bits` bits
232let mut sz = self.size + digits;
233if bits > 0 {
234let last = sz;
235let overflow = self.base[last - 1] >> (digitbits - bits);
236if overflow > 0 {
237self.base[last] = overflow;
238 sz += 1;
239 }
240for i in (digits + 1..last).rev() {
241self.base[i] =
242 (self.base[i] << bits) | (self.base[i - 1] >> (digitbits - bits));
243 }
244self.base[digits] <<= bits;
245// self.base[..digits] is zero, no need to shift
246}
247248self.size = sz;
249self
250}
251252/// Multiplies itself by `5^e` and returns its own mutable reference.
253pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name {
254use crate::num::imp::bignum::SMALL_POW5;
255256// There are exactly n trailing zeros on 2^n, and the only relevant digit sizes
257 // are consecutive powers of two, so this is well suited index for the table.
258let table_index = size_of::<$ty>().trailing_zeros() as usize;
259let (small_power, small_e) = SMALL_POW5[table_index];
260let small_power = small_power as $ty;
261262// Multiply with the largest single-digit power as long as possible ...
263while e >= small_e {
264self.mul_small(small_power);
265 e -= small_e;
266 }
267268// ... then finish off the remainder.
269let mut rest_power = 1;
270for _ in 0..e {
271 rest_power *= 5;
272 }
273self.mul_small(rest_power);
274275self
276}
277278/// Multiplies itself by a number described by `other[0] + other[1] * 2^W +
279 /// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type)
280 /// and returns its own mutable reference.
281pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name {
282// the internal routine. works best when aa.len() <= bb.len().
283fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize {
284use crate::num::imp::bignum::FullOps;
285286let mut retsz = 0;
287for (i, &a) in aa.iter().enumerate() {
288if a == 0 {
289continue;
290 }
291let mut sz = bb.len();
292let mut carry = 0;
293for (j, &b) in bb.iter().enumerate() {
294let (c, v) = a.full_mul_add(b, ret[i + j], carry);
295 ret[i + j] = v;
296 carry = c;
297 }
298if carry > 0 {
299 ret[i + sz] = carry;
300 sz += 1;
301 }
302if retsz < i + sz {
303 retsz = i + sz;
304 }
305 }
306 retsz
307 }
308309let mut ret = [0; $n];
310let retsz = if self.size < other.len() {
311 mul_inner(&mut ret, &self.digits(), other)
312 } else {
313 mul_inner(&mut ret, other, &self.digits())
314 };
315self.base = ret;
316self.size = retsz;
317self
318}
319320/// Divides itself by a digit-sized `other` and returns its own
321 /// mutable reference *and* the remainder.
322pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) {
323use crate::num::imp::bignum::FullOps;
324325assert!(other > 0);
326327let sz = self.size;
328let mut borrow = 0;
329for a in self.base[..sz].iter_mut().rev() {
330let (q, r) = (*a).full_div_rem(other, borrow);
331*a = q;
332 borrow = r;
333 }
334 (self, borrow)
335 }
336 }
337338impl crate::cmp::PartialEq for $name {
339fn eq(&self, other: &$name) -> bool {
340self.base[..] == other.base[..]
341 }
342 }
343344impl crate::cmp::Eq for $name {}
345346impl crate::cmp::PartialOrd for $name {
347fn partial_cmp(&self, other: &$name) -> crate::option::Option<crate::cmp::Ordering> {
348crate::option::Option::Some(self.cmp(other))
349 }
350 }
351352impl crate::cmp::Ord for $name {
353fn cmp(&self, other: &$name) -> crate::cmp::Ordering {
354use crate::cmp::max;
355let sz = max(self.size, other.size);
356let lhs = self.base[..sz].iter().cloned().rev();
357let rhs = other.base[..sz].iter().cloned().rev();
358 lhs.cmp(rhs)
359 }
360 }
361362impl crate::clone::Clone for $name {
363fn clone(&self) -> Self {
364Self { size: self.size, base: self.base }
365 }
366 }
367368impl crate::clone::UseCloned for $name {}
369370impl crate::fmt::Debug for $name {
371fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
372let sz = if self.size < 1 { 1 } else { self.size };
373let digitlen = <$ty>::BITS as usize / 4;
374375write!(f, "{:#x}", self.base[sz - 1])?;
376for &v in self.base[..sz - 1].iter().rev() {
377write!(f, "_{:01$x}", v, digitlen)?;
378 }
379crate::result::Result::Ok(())
380 }
381 }
382 };
383}
384385/// The digit type for `Big32x40`.
386pub type Digit32 = u32;
387388/// 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 Big32x40 {
/// 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: [Digit32; 40],
}
impl Big32x40 {
/// Makes a bignum from one digit.
pub fn from_small(v: Digit32) -> Big32x40 {
let mut base = [0; 40];
base[0] = v;
Big32x40 { size: 1, base }
}
/// Makes a bignum from `u64` value.
pub fn from_u64(mut v: u64) -> Big32x40 {
let mut base = [0; 40];
let mut sz = 0;
while v > 0 {
base[sz] = v as Digit32;
v >>= <Digit32>::BITS;
sz += 1;
}
Big32x40 { 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) -> &[Digit32] { &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 = <Digit32>::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 = <Digit32>::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: &Big32x40) -> &'a mut Big32x40 {
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: Digit32) -> &mut Big32x40 {
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: &Big32x40) -> &'a mut Big32x40 {
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: Digit32) -> &mut Big32x40 {
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 Big32x40 {
let digitbits = <Digit32>::BITS as usize;
let digits = bits / digitbits;
let bits = bits % digitbits;
if !(digits < 40) {
crate::panicking::panic("assertion failed: digits < 40")
};
if true {
if !self.base[40 - digits..].iter().all(|&v| v == 0) {
crate::panicking::panic("assertion failed: self.base[40 - digits..].iter().all(|&v| v == 0)")
};
};
if true {
if !(bits == 0 ||
(self.base[40 - digits - 1] >> (digitbits - bits)) == 0) {
crate::panicking::panic("assertion failed: bits == 0 || (self.base[40 - 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 Big32x40 {
use crate::num::imp::bignum::SMALL_POW5;
let table_index = size_of::<Digit32>().trailing_zeros() as usize;
let (small_power, small_e) = SMALL_POW5[table_index];
let small_power = small_power as Digit32;
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: &[Digit32])
-> &'a mut Big32x40 {
fn mul_inner(ret: &mut [Digit32; 40], aa: &[Digit32], bb: &[Digit32])
-> 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; 40];
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: Digit32)
-> (&mut Big32x40, Digit32) {
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 Big32x40 {
fn eq(&self, other: &Big32x40) -> bool { self.base[..] == other.base[..] }
}
impl crate::cmp::Eq for Big32x40 {}
impl crate::cmp::PartialOrd for Big32x40 {
fn partial_cmp(&self, other: &Big32x40)
-> crate::option::Option<crate::cmp::Ordering> {
crate::option::Option::Some(self.cmp(other))
}
}
impl crate::cmp::Ord for Big32x40 {
fn cmp(&self, other: &Big32x40) -> 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 Big32x40 {
fn clone(&self) -> Self { Self { size: self.size, base: self.base } }
}
impl crate::clone::UseCloned for Big32x40 {}
impl crate::fmt::Debug for Big32x40 {
fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
let sz = if self.size < 1 { 1 } else { self.size };
let digitlen = <Digit32>::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!(Big32x40: type=Digit32, n=40);
389390// this one is used for testing only.
391#[doc(hidden)]
392pub mod tests {
393/// 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 >>= <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);
394}