use crate::large_powers;
use crate::lib::ops::RangeBounds;
use crate::lib::{cmp, iter, mem, ops, ptr};
use crate::num::*;
use crate::slice::*;
use crate::small_powers::*;
#[cfg(limb_width_32)]
pub type Limb = u32;
#[cfg(limb_width_32)]
pub const POW5_LIMB: &[Limb] = &POW5_32;
#[cfg(limb_width_32)]
pub const POW10_LIMB: &[Limb] = &POW10_32;
#[cfg(limb_width_32)]
type Wide = u64;
#[cfg(limb_width_64)]
pub type Limb = u64;
#[cfg(limb_width_64)]
pub const POW5_LIMB: &[Limb] = &POW5_64;
#[cfg(limb_width_64)]
pub const POW10_LIMB: &[Limb] = &POW10_64;
#[cfg(limb_width_64)]
type Wide = u128;
#[cfg(all(feature = "no_alloc", limb_width_32))]
pub(crate) type LimbVecType = arrayvec::ArrayVec<[Limb; 128]>;
#[cfg(all(feature = "no_alloc", limb_width_64))]
pub(crate) type LimbVecType = arrayvec::ArrayVec<[Limb; 64]>;
#[cfg(not(feature = "no_alloc"))]
pub(crate) type LimbVecType = crate::lib::Vec<Limb>;
#[inline(always)]
pub(crate) fn as_limb<T: Integer>(t: T) -> Limb {
Limb::as_cast(t)
}
#[inline(always)]
fn as_wide<T: Integer>(t: T) -> Wide {
Wide::as_cast(t)
}
#[inline]
#[cfg(limb_width_32)]
fn split_u64(x: u64) -> [Limb; 2] {
[as_limb(x), as_limb(x >> 32)]
}
#[inline]
#[cfg(limb_width_64)]
fn split_u64(x: u64) -> [Limb; 1] {
[as_limb(x)]
}
#[inline]
pub fn nonzero<T: Integer>(x: &[T], rindex: usize) -> bool {
let len = x.len();
let slc = &x[..len - rindex];
slc.iter().rev().any(|&x| x != T::ZERO)
}
#[inline]
fn u64_to_hi64_1(r0: u64) -> (u64, bool) {
debug_assert!(r0 != 0);
let ls = r0.leading_zeros();
(r0 << ls, false)
}
#[inline]
fn u64_to_hi64_2(r0: u64, r1: u64) -> (u64, bool) {
debug_assert!(r0 != 0);
let ls = r0.leading_zeros();
let rs = 64 - ls;
let v = match ls {
0 => r0,
_ => (r0 << ls) | (r1 >> rs),
};
let n = r1 << ls != 0;
(v, n)
}
trait Hi64<T>: Slice<T> {
fn hi64_1(&self) -> (u64, bool);
fn hi64_2(&self) -> (u64, bool);
fn hi64_3(&self) -> (u64, bool);
fn hi64_4(&self) -> (u64, bool);
fn hi64_5(&self) -> (u64, bool);
#[inline]
fn hi64(&self) -> (u64, bool) {
match self.len() {
0 => (0, false),
1 => self.hi64_1(),
2 => self.hi64_2(),
3 => self.hi64_3(),
4 => self.hi64_4(),
_ => self.hi64_5(),
}
}
}
impl Hi64<u32> for [u32] {
#[inline]
fn hi64_1(&self) -> (u64, bool) {
debug_assert!(self.len() == 1);
let rview = self.rview();
let r0 = rview[0].as_u64();
u64_to_hi64_1(r0)
}
#[inline]
fn hi64_2(&self) -> (u64, bool) {
debug_assert!(self.len() == 2);
let rview = self.rview();
let r0 = rview[0].as_u64() << 32;
let r1 = rview[1].as_u64();
u64_to_hi64_1(r0 | r1)
}
#[inline]
fn hi64_3(&self) -> (u64, bool) {
debug_assert!(self.len() >= 3);
let rview = self.rview();
let r0 = rview[0].as_u64();
let r1 = rview[1].as_u64() << 32;
let r2 = rview[2].as_u64();
let (v, n) = u64_to_hi64_2(r0, r1 | r2);
(v, n || nonzero(self, 3))
}
#[inline]
fn hi64_4(&self) -> (u64, bool) {
self.hi64_3()
}
#[inline]
fn hi64_5(&self) -> (u64, bool) {
self.hi64_3()
}
}
impl Hi64<u64> for [u64] {
#[inline]
fn hi64_1(&self) -> (u64, bool) {
debug_assert!(self.len() == 1);
let rview = self.rview();
let r0 = rview[0];
u64_to_hi64_1(r0)
}
#[inline]
fn hi64_2(&self) -> (u64, bool) {
debug_assert!(self.len() >= 2);
let rview = self.rview();
let r0 = rview[0];
let r1 = rview[1];
let (v, n) = u64_to_hi64_2(r0, r1);
(v, n || nonzero(self, 2))
}
#[inline]
fn hi64_3(&self) -> (u64, bool) {
self.hi64_2()
}
#[inline]
fn hi64_4(&self) -> (u64, bool) {
self.hi64_2()
}
#[inline]
fn hi64_5(&self) -> (u64, bool) {
self.hi64_2()
}
}
pub fn insert_many<Iter>(vec: &mut LimbVecType, index: usize, iterable: Iter)
where
Iter: iter::IntoIterator<Item = Limb>,
{
let mut iter = iterable.into_iter();
if index == vec.len() {
return vec.extend(iter);
}
let (lower_size_bound, _) = iter.size_hint();
assert!(lower_size_bound <= core::isize::MAX as usize); assert!(index + lower_size_bound >= index);
let mut num_added = 0;
let old_len = vec.len();
assert!(index <= old_len);
unsafe {
reserve(vec, lower_size_bound);
let start = vec.as_mut_ptr();
let ptr = start.add(index);
ptr::copy(ptr, ptr.add(lower_size_bound), old_len - index);
vec.set_len(0);
let mut guard = DropOnPanic {
start,
skip: index..(index + lower_size_bound),
len: old_len + lower_size_bound,
};
while num_added < lower_size_bound {
let element = match iter.next() {
Some(x) => x,
None => break,
};
let cur = ptr.add(num_added);
ptr::write(cur, element);
guard.skip.start += 1;
num_added += 1;
}
if num_added < lower_size_bound {
ptr::copy(ptr.add(lower_size_bound), ptr.add(num_added), old_len - index);
}
vec.set_len(old_len + num_added);
mem::forget(guard);
}
for element in iter {
vec.insert(index + num_added, element);
num_added += 1;
}
struct DropOnPanic<T> {
start: *mut T,
skip: ops::Range<usize>, len: usize,
}
impl<T> DropOnPanic<T> {
#[inline]
fn contains(&self, item: &usize) -> bool {
(match self.skip.start_bound() {
ops::Bound::Included(ref start) => *start <= item,
ops::Bound::Excluded(ref start) => *start < item,
ops::Bound::Unbounded => true,
}) && (match self.skip.end_bound() {
ops::Bound::Included(ref end) => item <= *end,
ops::Bound::Excluded(ref end) => item < *end,
ops::Bound::Unbounded => true,
})
}
}
impl<T> Drop for DropOnPanic<T> {
fn drop(&mut self) {
for i in 0..self.len {
if !self.contains(&i) {
unsafe {
ptr::drop_in_place(self.start.add(i));
}
}
}
}
}
}
#[inline]
#[cfg(feature = "no_alloc")]
fn resize(vec: &mut LimbVecType, len: usize, value: Limb) {
assert!(len <= vec.capacity());
let old_len = vec.len();
if len > old_len {
vec.extend(iter::repeat(value).take(len - old_len));
} else {
vec.truncate(len);
}
}
#[inline]
#[cfg(not(feature = "no_alloc"))]
fn resize(vec: &mut LimbVecType, len: usize, value: Limb) {
vec.resize(len, value)
}
#[inline]
#[cfg(feature = "no_alloc")]
pub(crate) fn reserve(vec: &mut LimbVecType, capacity: usize) {
assert!(vec.len() + capacity <= vec.capacity());
}
#[inline]
#[cfg(not(feature = "no_alloc"))]
pub(crate) fn reserve(vec: &mut LimbVecType, capacity: usize) {
vec.reserve(capacity)
}
#[inline]
#[cfg(feature = "no_alloc")]
fn reserve_exact(vec: &mut LimbVecType, capacity: usize) {
assert!(vec.len() + capacity <= vec.capacity());
}
#[inline]
#[cfg(not(feature = "no_alloc"))]
fn reserve_exact(vec: &mut LimbVecType, capacity: usize) {
vec.reserve_exact(capacity)
}
mod scalar {
use super::*;
#[inline]
pub fn add(x: Limb, y: Limb) -> (Limb, bool) {
x.overflowing_add(y)
}
#[inline]
pub fn iadd(x: &mut Limb, y: Limb) -> bool {
let t = add(*x, y);
*x = t.0;
t.1
}
#[inline]
pub fn sub(x: Limb, y: Limb) -> (Limb, bool) {
x.overflowing_sub(y)
}
#[inline]
pub fn isub(x: &mut Limb, y: Limb) -> bool {
let t = sub(*x, y);
*x = t.0;
t.1
}
#[inline]
pub fn mul(x: Limb, y: Limb, carry: Limb) -> (Limb, Limb) {
let z: Wide = as_wide(x) * as_wide(y) + as_wide(carry);
let bits = mem::size_of::<Limb>() * 8;
(as_limb(z), as_limb(z >> bits))
}
#[inline]
pub fn imul(x: &mut Limb, y: Limb, carry: Limb) -> Limb {
let t = mul(*x, y, carry);
*x = t.0;
t.1
}
}
mod small {
use super::*;
#[inline]
pub fn iadd_impl(x: &mut LimbVecType, y: Limb, xstart: usize) {
if x.len() <= xstart {
x.push(y);
} else {
let mut carry = scalar::iadd(&mut x[xstart], y);
let mut size = xstart + 1;
while carry && size < x.len() {
carry = scalar::iadd(&mut x[size], 1);
size += 1;
}
if carry {
x.push(1);
}
}
}
#[inline]
pub fn iadd(x: &mut LimbVecType, y: Limb) {
iadd_impl(x, y, 0);
}
#[inline]
pub fn isub_impl(x: &mut LimbVecType, y: Limb, xstart: usize) {
debug_assert!(x.len() > xstart && (x[xstart] >= y || x.len() > xstart + 1));
let mut carry = scalar::isub(&mut x[xstart], y);
let mut size = xstart + 1;
while carry && size < x.len() {
carry = scalar::isub(&mut x[size], 1);
size += 1;
}
normalize(x);
}
#[inline]
pub fn imul(x: &mut LimbVecType, y: Limb) {
let mut carry: Limb = 0;
for xi in x.iter_mut() {
carry = scalar::imul(xi, y, carry);
}
if carry != 0 {
x.push(carry);
}
}
#[inline]
pub fn mul(x: &[Limb], y: Limb) -> LimbVecType {
let mut z = LimbVecType::default();
z.extend(x.iter().cloned());
imul(&mut z, y);
z
}
pub fn imul_pow5(x: &mut LimbVecType, n: u32) {
use super::large::KARATSUBA_CUTOFF;
let small_powers = POW5_LIMB;
let large_powers = large_powers::POW5;
if n == 0 {
return;
}
let bit_length = 32 - n.leading_zeros().as_usize();
debug_assert!(bit_length != 0 && bit_length <= large_powers.len());
if x.len() + large_powers[bit_length - 1].len() < 2 * KARATSUBA_CUTOFF {
let step = small_powers.len() - 1;
let power = small_powers[step];
let mut n = n.as_usize();
while n >= step {
imul(x, power);
n -= step;
}
imul(x, small_powers[n]);
} else {
let mut idx: usize = 0;
let mut bit: usize = 1;
let mut n = n.as_usize();
while n != 0 {
if n & bit != 0 {
debug_assert!(idx < large_powers.len());
large::imul(x, large_powers[idx]);
n ^= bit;
}
idx += 1;
bit <<= 1;
}
}
}
#[inline]
pub fn leading_zeros(x: &[Limb]) -> usize {
if x.is_empty() {
0
} else {
x.rindex(0).leading_zeros().as_usize()
}
}
#[inline]
pub fn bit_length(x: &[Limb]) -> usize {
let bits = mem::size_of::<Limb>() * 8;
let nlz = leading_zeros(x);
bits.checked_mul(x.len()).map(|v| v - nlz).unwrap_or(usize::max_value())
}
#[inline]
pub fn ishl_bits(x: &mut LimbVecType, n: usize) {
let bits = mem::size_of::<Limb>() * 8;
debug_assert!(n < bits);
if n == 0 {
return;
}
let rshift = bits - n;
let lshift = n;
let mut prev: Limb = 0;
for xi in x.iter_mut() {
let tmp = *xi;
*xi <<= lshift;
*xi |= prev >> rshift;
prev = tmp;
}
let carry = prev >> rshift;
if carry != 0 {
x.push(carry);
}
}
#[inline]
pub fn ishl_limbs(x: &mut LimbVecType, n: usize) {
debug_assert!(n != 0);
if !x.is_empty() {
insert_many(x, 0, iter::repeat(0).take(n));
}
}
#[inline]
pub fn ishl(x: &mut LimbVecType, n: usize) {
let bits = mem::size_of::<Limb>() * 8;
let rem = n % bits;
let div = n / bits;
ishl_bits(x, rem);
if div != 0 {
ishl_limbs(x, div);
}
}
#[inline]
pub fn normalize(x: &mut LimbVecType) {
while !x.is_empty() && *x.rindex(0) == 0 {
x.pop();
}
}
}
mod large {
use super::*;
#[inline]
pub fn compare(x: &[Limb], y: &[Limb]) -> cmp::Ordering {
if x.len() > y.len() {
return cmp::Ordering::Greater;
} else if x.len() < y.len() {
return cmp::Ordering::Less;
} else {
let iter = x.iter().rev().zip(y.iter().rev());
for (&xi, &yi) in iter {
if xi > yi {
return cmp::Ordering::Greater;
} else if xi < yi {
return cmp::Ordering::Less;
}
}
return cmp::Ordering::Equal;
}
}
#[inline]
pub fn less(x: &[Limb], y: &[Limb]) -> bool {
compare(x, y) == cmp::Ordering::Less
}
#[inline]
pub fn greater_equal(x: &[Limb], y: &[Limb]) -> bool {
!less(x, y)
}
pub fn iadd_impl(x: &mut LimbVecType, y: &[Limb], xstart: usize) {
if y.len() > x.len() - xstart {
resize(x, y.len() + xstart, 0);
}
let mut carry = false;
for (xi, yi) in (&mut x[xstart..]).iter_mut().zip(y.iter()) {
let mut tmp = scalar::iadd(xi, *yi);
if carry {
tmp |= scalar::iadd(xi, 1);
}
carry = tmp;
}
if carry {
small::iadd_impl(x, 1, y.len() + xstart);
}
}
#[inline]
pub fn iadd(x: &mut LimbVecType, y: &[Limb]) {
iadd_impl(x, y, 0)
}
#[inline]
pub fn add(x: &[Limb], y: &[Limb]) -> LimbVecType {
let mut z = LimbVecType::default();
z.extend(x.iter().cloned());
iadd(&mut z, y);
z
}
pub fn isub(x: &mut LimbVecType, y: &[Limb]) {
debug_assert!(greater_equal(x, y));
let mut carry = false;
for (xi, yi) in x.iter_mut().zip(y.iter()) {
let mut tmp = scalar::isub(xi, *yi);
if carry {
tmp |= scalar::isub(xi, 1);
}
carry = tmp;
}
if carry {
small::isub_impl(x, 1, y.len());
} else {
small::normalize(x);
}
}
pub const KARATSUBA_CUTOFF: usize = 32;
fn long_mul(x: &[Limb], y: &[Limb]) -> LimbVecType {
let mut z: LimbVecType = small::mul(x, y[0]);
resize(&mut z, x.len() + y.len(), 0);
for (i, &yi) in y[1..].iter().enumerate() {
let zi: LimbVecType = small::mul(x, yi);
iadd_impl(&mut z, &zi, i + 1);
}
small::normalize(&mut z);
z
}
#[inline]
pub fn karatsuba_split<'a>(z: &'a [Limb], m: usize) -> (&'a [Limb], &'a [Limb]) {
(&z[..m], &z[m..])
}
fn karatsuba_mul(x: &[Limb], y: &[Limb]) -> LimbVecType {
if y.len() <= KARATSUBA_CUTOFF {
long_mul(x, y)
} else if x.len() < y.len() / 2 {
karatsuba_uneven_mul(x, y)
} else {
let m = y.len() / 2;
let (xl, xh) = karatsuba_split(x, m);
let (yl, yh) = karatsuba_split(y, m);
let sumx = add(xl, xh);
let sumy = add(yl, yh);
let z0 = karatsuba_mul(xl, yl);
let mut z1 = karatsuba_mul(&sumx, &sumy);
let z2 = karatsuba_mul(xh, yh);
isub(&mut z1, &z2);
isub(&mut z1, &z0);
let mut result = LimbVecType::default();
let len = z0.len().max(m + z1.len()).max(2 * m + z2.len());
reserve_exact(&mut result, len);
result.extend(z0.iter().cloned());
iadd_impl(&mut result, &z1, m);
iadd_impl(&mut result, &z2, 2 * m);
result
}
}
fn karatsuba_uneven_mul(x: &[Limb], mut y: &[Limb]) -> LimbVecType {
let mut result = LimbVecType::default();
resize(&mut result, x.len() + y.len(), 0);
let mut start = 0;
while y.len() != 0 {
let m = x.len().min(y.len());
let (yl, yh) = karatsuba_split(y, m);
let prod = karatsuba_mul(x, yl);
iadd_impl(&mut result, &prod, start);
y = yh;
start += m;
}
small::normalize(&mut result);
result
}
#[inline]
fn karatsuba_mul_fwd(x: &[Limb], y: &[Limb]) -> LimbVecType {
if x.len() < y.len() {
karatsuba_mul(x, y)
} else {
karatsuba_mul(y, x)
}
}
#[inline]
pub fn imul(x: &mut LimbVecType, y: &[Limb]) {
if y.len() == 1 {
small::imul(x, y[0]);
} else {
*x = karatsuba_mul_fwd(x, y);
}
}
}
pub(crate) trait Math: Clone + Sized + Default {
fn data<'a>(&'a self) -> &'a LimbVecType;
fn data_mut<'a>(&'a mut self) -> &'a mut LimbVecType;
#[inline]
fn compare(&self, y: &Self) -> cmp::Ordering {
large::compare(self.data(), y.data())
}
#[inline]
fn hi64(&self) -> (u64, bool) {
self.data().as_slice().hi64()
}
#[inline]
fn bit_length(&self) -> usize {
small::bit_length(self.data())
}
#[inline]
fn from_u64(x: u64) -> Self {
let mut v = Self::default();
let slc = split_u64(x);
v.data_mut().extend(slc.iter().cloned());
v.normalize();
v
}
#[inline]
fn normalize(&mut self) {
small::normalize(self.data_mut());
}
#[inline]
fn iadd_small(&mut self, y: Limb) {
small::iadd(self.data_mut(), y);
}
#[inline]
fn imul_small(&mut self, y: Limb) {
small::imul(self.data_mut(), y);
}
#[inline]
fn imul_pow2(&mut self, n: u32) {
self.ishl(n.as_usize())
}
#[inline]
fn imul_pow5(&mut self, n: u32) {
small::imul_pow5(self.data_mut(), n)
}
#[inline]
fn imul_pow10(&mut self, n: u32) {
self.imul_pow5(n);
self.imul_pow2(n);
}
#[inline]
fn ishl(&mut self, n: usize) {
small::ishl(self.data_mut(), n);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Default)]
struct Bigint {
data: LimbVecType,
}
impl Math for Bigint {
#[inline]
fn data<'a>(&'a self) -> &'a LimbVecType {
&self.data
}
#[inline]
fn data_mut<'a>(&'a mut self) -> &'a mut LimbVecType {
&mut self.data
}
}
#[cfg(limb_width_32)]
pub(crate) fn from_u32(x: &[u32]) -> LimbVecType {
x.iter().cloned().collect()
}
#[cfg(limb_width_64)]
pub(crate) fn from_u32(x: &[u32]) -> LimbVecType {
let mut v = LimbVecType::default();
for xi in x.chunks(2) {
match xi.len() {
1 => v.push(xi[0] as u64),
2 => v.push(((xi[1] as u64) << 32) | (xi[0] as u64)),
_ => unreachable!(),
}
}
v
}
#[test]
fn compare_test() {
let x = Bigint {
data: from_u32(&[1]),
};
let y = Bigint {
data: from_u32(&[2]),
};
assert_eq!(x.compare(&y), cmp::Ordering::Less);
assert_eq!(x.compare(&x), cmp::Ordering::Equal);
assert_eq!(y.compare(&x), cmp::Ordering::Greater);
let x = Bigint {
data: from_u32(&[5, 1]),
};
let y = Bigint {
data: from_u32(&[2]),
};
assert_eq!(x.compare(&y), cmp::Ordering::Greater);
assert_eq!(x.compare(&x), cmp::Ordering::Equal);
assert_eq!(y.compare(&x), cmp::Ordering::Less);
let x = Bigint {
data: from_u32(&[5, 1, 9]),
};
let y = Bigint {
data: from_u32(&[6, 2, 8]),
};
assert_eq!(x.compare(&y), cmp::Ordering::Greater);
assert_eq!(x.compare(&x), cmp::Ordering::Equal);
assert_eq!(y.compare(&x), cmp::Ordering::Less);
let x = Bigint {
data: from_u32(&[0, 1, 9]),
};
let y = Bigint {
data: from_u32(&[4294967295, 0, 9]),
};
assert_eq!(x.compare(&y), cmp::Ordering::Greater);
assert_eq!(x.compare(&x), cmp::Ordering::Equal);
assert_eq!(y.compare(&x), cmp::Ordering::Less);
}
#[test]
fn hi64_test() {
assert_eq!(Bigint::from_u64(0xA).hi64(), (0xA000000000000000, false));
assert_eq!(Bigint::from_u64(0xAB).hi64(), (0xAB00000000000000, false));
assert_eq!(Bigint::from_u64(0xAB00000000).hi64(), (0xAB00000000000000, false));
assert_eq!(Bigint::from_u64(0xA23456789A).hi64(), (0xA23456789A000000, false));
}
#[test]
fn bit_length_test() {
let x = Bigint {
data: from_u32(&[0, 0, 0, 1]),
};
assert_eq!(x.bit_length(), 97);
let x = Bigint {
data: from_u32(&[0, 0, 0, 3]),
};
assert_eq!(x.bit_length(), 98);
let x = Bigint {
data: from_u32(&[1 << 31]),
};
assert_eq!(x.bit_length(), 32);
}
#[test]
fn iadd_small_test() {
let mut x = Bigint {
data: from_u32(&[4294967295]),
};
x.iadd_small(5);
assert_eq!(x.data, from_u32(&[4, 1]));
let mut x = Bigint {
data: from_u32(&[5]),
};
x.iadd_small(7);
assert_eq!(x.data, from_u32(&[12]));
let mut x = Bigint::from_u64(0x80000000FFFFFFFF);
x.iadd_small(7);
assert_eq!(x.data, from_u32(&[6, 0x80000001]));
let mut x = Bigint::from_u64(0xFFFFFFFFFFFFFFFF);
x.iadd_small(7);
assert_eq!(x.data, from_u32(&[6, 0, 1]));
}
#[test]
fn imul_small_test() {
let mut x = Bigint {
data: from_u32(&[5]),
};
x.imul_small(7);
assert_eq!(x.data, from_u32(&[35]));
let mut x = Bigint::from_u64(0x4000000040000);
x.imul_small(5);
assert_eq!(x.data, from_u32(&[0x00140000, 0x140000]));
let mut x = Bigint {
data: from_u32(&[0x33333334]),
};
x.imul_small(5);
assert_eq!(x.data, from_u32(&[4, 1]));
let mut x = Bigint::from_u64(0x133333334);
x.imul_small(5);
assert_eq!(x.data, from_u32(&[4, 6]));
let mut x = Bigint::from_u64(0x3333333333333334);
x.imul_small(5);
assert_eq!(x.data, from_u32(&[4, 0, 1]));
}
#[test]
fn shl_test() {
let mut big = Bigint {
data: from_u32(&[0xD2210408]),
};
big.ishl(5);
assert_eq!(big.data, from_u32(&[0x44208100, 0x1A]));
big.ishl(32);
assert_eq!(big.data, from_u32(&[0, 0x44208100, 0x1A]));
big.ishl(27);
assert_eq!(big.data, from_u32(&[0, 0, 0xD2210408]));
let mut big = Bigint {
data: from_u32(&[0x20020010, 0x8040100, 0xD2210408]),
};
big.ishl(5);
assert_eq!(big.data, from_u32(&[0x400200, 0x802004, 0x44208101, 0x1A]));
big.ishl(32);
assert_eq!(big.data, from_u32(&[0, 0x400200, 0x802004, 0x44208101, 0x1A]));
big.ishl(27);
assert_eq!(big.data, from_u32(&[0, 0, 0x20020010, 0x8040100, 0xD2210408]));
}
}