// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. /*! A Big integer (signed version: BigInt, unsigned version: BigUint). A BigUint is represented as an array of BigDigits. A BigInt is a combination of BigUint and Sign. */ use core::cmp::{Eq, Ord}; use core::num::{IntConvertible, Zero, One}; use core::*; /** A BigDigit is a BigUint's composing element. A BigDigit is half the size of machine word size. */ #[cfg(target_arch = "x86")] #[cfg(target_arch = "arm")] #[cfg(target_arch = "mips")] pub type BigDigit = u16; /** A BigDigit is a BigUint's composing element. A BigDigit is half the size of machine word size. */ #[cfg(target_arch = "x86_64")] pub type BigDigit = u32; pub mod BigDigit { use bigint::BigDigit; #[cfg(target_arch = "x86")] #[cfg(target_arch = "arm")] #[cfg(target_arch = "mips")] pub static bits: uint = 16; #[cfg(target_arch = "x86_64")] pub static bits: uint = 32; pub static base: uint = 1 << bits; priv static hi_mask: uint = (-1 as uint) << bits; priv static lo_mask: uint = (-1 as uint) >> bits; priv fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit } priv fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit } /// Split one machine sized unsigned integer into two BigDigits. pub fn from_uint(n: uint) -> (BigDigit, BigDigit) { (get_hi(n), get_lo(n)) } /// Join two BigDigits into one machine sized unsigned integer pub fn to_uint(hi: BigDigit, lo: BigDigit) -> uint { (lo as uint) | ((hi as uint) << bits) } } /** A big unsigned integer type. A BigUint-typed value BigUint { data: @[a, b, c] } represents a number (a + b * BigDigit::base + c * BigDigit::base^2). */ pub struct BigUint { priv data: ~[BigDigit] } impl Eq for BigUint { fn eq(&self, other: &BigUint) -> bool { self.cmp(other) == 0 } fn ne(&self, other: &BigUint) -> bool { self.cmp(other) != 0 } } impl Ord for BigUint { fn lt(&self, other: &BigUint) -> bool { self.cmp(other) < 0 } fn le(&self, other: &BigUint) -> bool { self.cmp(other) <= 0 } fn ge(&self, other: &BigUint) -> bool { self.cmp(other) >= 0 } fn gt(&self, other: &BigUint) -> bool { self.cmp(other) > 0 } } impl ToStr for BigUint { fn to_str(&self) -> ~str { self.to_str_radix(10) } } impl from_str::FromStr for BigUint { fn from_str(s: &str) -> Option { BigUint::from_str_radix(s, 10) } } impl Shl for BigUint { fn shl(&self, rhs: &uint) -> BigUint { let n_unit = *rhs / BigDigit::bits; let n_bits = *rhs % BigDigit::bits; return self.shl_unit(n_unit).shl_bits(n_bits); } } impl Shr for BigUint { fn shr(&self, rhs: &uint) -> BigUint { let n_unit = *rhs / BigDigit::bits; let n_bits = *rhs % BigDigit::bits; return self.shr_unit(n_unit).shr_bits(n_bits); } } impl Zero for BigUint { fn zero() -> BigUint { BigUint::new(~[]) } } impl One for BigUint { pub fn one() -> BigUint { BigUint::new(~[1]) } } impl Add for BigUint { fn add(&self, other: &BigUint) -> BigUint { let new_len = uint::max(self.data.len(), other.data.len()); let mut carry = 0; let sum = do vec::from_fn(new_len) |i| { let ai = if i < self.data.len() { self.data[i] } else { 0 }; let bi = if i < other.data.len() { other.data[i] } else { 0 }; let (hi, lo) = BigDigit::from_uint( (ai as uint) + (bi as uint) + (carry as uint) ); carry = hi; lo }; if carry == 0 { return BigUint::new(sum) }; return BigUint::new(sum + [carry]); } } impl Sub for BigUint { fn sub(&self, other: &BigUint) -> BigUint { let new_len = uint::max(self.data.len(), other.data.len()); let mut borrow = 0; let diff = do vec::from_fn(new_len) |i| { let ai = if i < self.data.len() { self.data[i] } else { 0 }; let bi = if i < other.data.len() { other.data[i] } else { 0 }; let (hi, lo) = BigDigit::from_uint( (BigDigit::base) + (ai as uint) - (bi as uint) - (borrow as uint) ); /* hi * (base) + lo == 1*(base) + ai - bi - borrow => ai - bi - borrow < 0 <=> hi == 0 */ borrow = if hi == 0 { 1 } else { 0 }; lo }; fail_unless!(borrow == 0); // <=> fail_unless!((self >= other)); return BigUint::new(diff); } } impl Mul for BigUint { fn mul(&self, other: &BigUint) -> BigUint { if self.is_zero() || other.is_zero() { return Zero::zero(); } let s_len = self.data.len(), o_len = other.data.len(); if s_len == 1 { return mul_digit(other, self.data[0]); } if o_len == 1 { return mul_digit(self, other.data[0]); } // Using Karatsuba multiplication // (a1 * base + a0) * (b1 * base + b0) // = a1*b1 * base^2 + // (a1*b1 + a0*b0 - (a1-b0)*(b1-a0)) * base + // a0*b0 let half_len = uint::max(s_len, o_len) / 2; let (sHi, sLo) = cut_at(self, half_len); let (oHi, oLo) = cut_at(other, half_len); let ll = sLo * oLo; let hh = sHi * oHi; let mm = { let (s1, n1) = sub_sign(sHi, sLo); let (s2, n2) = sub_sign(oHi, oLo); if s1 * s2 < 0 { hh + ll + (n1 * n2) } else if s1 * s2 > 0 { hh + ll - (n1 * n2) } else { hh + ll } }; return ll + mm.shl_unit(half_len) + hh.shl_unit(half_len * 2); fn mul_digit(a: &BigUint, n: BigDigit) -> BigUint { if n == 0 { return Zero::zero(); } if n == 1 { return copy *a; } let mut carry = 0; let prod = do vec::map(a.data) |ai| { let (hi, lo) = BigDigit::from_uint( (*ai as uint) * (n as uint) + (carry as uint) ); carry = hi; lo }; if carry == 0 { return BigUint::new(prod) }; return BigUint::new(prod + [carry]); } fn cut_at(a: &BigUint, n: uint) -> (BigUint, BigUint) { let mid = uint::min(a.data.len(), n); return (BigUint::from_slice(vec::slice(a.data, mid, a.data.len())), BigUint::from_slice(vec::slice(a.data, 0, mid))); } fn sub_sign(a: BigUint, b: BigUint) -> (int, BigUint) { match a.cmp(&b) { s if s < 0 => (s, b - a), s if s > 0 => (s, a - b), _ => (0, Zero::zero()) } } } } impl Div for BigUint { fn div(&self, other: &BigUint) -> BigUint { let (d, _) = self.divmod(other); return d; } } impl Modulo for BigUint { fn modulo(&self, other: &BigUint) -> BigUint { let (_, m) = self.divmod(other); return m; } } impl Neg for BigUint { fn neg(&self) -> BigUint { fail!() } } impl IntConvertible for BigUint { fn to_int(&self) -> int { uint::min(self.to_uint(), int::max_value as uint) as int } fn from_int(n: int) -> BigUint { if (n < 0) { Zero::zero() } else { BigUint::from_uint(n as uint) } } } pub impl BigUint { /// Creates and initializes an BigUint. pub fn new(v: ~[BigDigit]) -> BigUint { // omit trailing zeros let new_len = v.rposition(|n| *n != 0).map_default(0, |p| *p + 1); if new_len == v.len() { return BigUint { data: v }; } let mut v = v; unsafe { v.truncate(new_len); } return BigUint { data: v }; } /// Creates and initializes an BigUint. pub fn from_uint(n: uint) -> BigUint { match BigDigit::from_uint(n) { (0, 0) => Zero::zero(), (0, n0) => BigUint::new(~[n0]), (n1, n0) => BigUint::new(~[n0, n1]) } } /// Creates and initializes an BigUint. pub fn from_slice(slice: &[BigDigit]) -> BigUint { return BigUint::new(vec::from_slice(slice)); } /// Creates and initializes an BigUint. pub fn from_str_radix(s: &str, radix: uint) -> Option { BigUint::parse_bytes(str::to_bytes(s), radix) } /// Creates and initializes an BigUint. pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { let (base, unit_len) = get_radix_base(radix); let base_num: BigUint = BigUint::from_uint(base); let mut end = buf.len(); let mut n: BigUint = Zero::zero(); let mut power: BigUint = One::one(); loop { let start = uint::max(end, unit_len) - unit_len; match uint::parse_bytes(vec::slice(buf, start, end), radix) { Some(d) => n += BigUint::from_uint(d) * power, None => return None } if end <= unit_len { return Some(n); } end -= unit_len; power *= base_num; } } fn abs(&self) -> BigUint { copy *self } /// Compare two BigUint value. fn cmp(&self, other: &BigUint) -> int { let s_len = self.data.len(), o_len = other.data.len(); if s_len < o_len { return -1; } if s_len > o_len { return 1; } for self.data.eachi_reverse |i, elm| { match (*elm, other.data[i]) { (l, r) if l < r => return -1, (l, r) if l > r => return 1, _ => loop }; } return 0; } fn divmod(&self, other: &BigUint) -> (BigUint, BigUint) { if other.is_zero() { fail!() } if self.is_zero() { return (Zero::zero(), Zero::zero()); } if *other == One::one() { return (copy *self, Zero::zero()); } match self.cmp(other) { s if s < 0 => return (Zero::zero(), copy *self), 0 => return (One::one(), Zero::zero()), _ => {} // Do nothing } let mut shift = 0; let mut n = *other.data.last(); while n < (1 << BigDigit::bits - 2) { n <<= 1; shift += 1; } fail_unless!(shift < BigDigit::bits); let (d, m) = divmod_inner(self << shift, other << shift); return (d, m >> shift); fn divmod_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) { let mut r = a; let mut d = Zero::zero::(); let mut n = 1; while r >= b { let mut (d0, d_unit, b_unit) = div_estimate(&r, &b, n); let mut prod = b * d0; while prod > r { d0 -= d_unit; prod -= b_unit; } if d0.is_zero() { n = 2; loop; } n = 1; d += d0; r -= prod; } return (d, r); } fn div_estimate(a: &BigUint, b: &BigUint, n: uint) -> (BigUint, BigUint, BigUint) { if a.data.len() < n { return (Zero::zero(), Zero::zero(), copy *a); } let an = vec::slice(a.data, a.data.len() - n, a.data.len()); let bn = *b.data.last(); let mut d = ~[]; let mut carry = 0; for an.each_reverse |elt| { let ai = BigDigit::to_uint(carry, *elt); let di = ai / (bn as uint); fail_unless!(di < BigDigit::base); carry = (ai % (bn as uint)) as BigDigit; d = ~[di as BigDigit] + d; } let shift = (a.data.len() - an.len()) - (b.data.len() - 1); if shift == 0 { return (BigUint::new(d), One::one(), copy *b); } return (BigUint::from_slice(d).shl_unit(shift), One::one::().shl_unit(shift), b.shl_unit(shift)); } } fn quot(&self, other: &BigUint) -> BigUint { let (q, _) = self.quotrem(other); return q; } fn rem(&self, other: &BigUint) -> BigUint { let (_, r) = self.quotrem(other); return r; } fn quotrem(&self, other: &BigUint) -> (BigUint, BigUint) { self.divmod(other) } fn is_zero(&self) -> bool { self.data.is_empty() } fn is_not_zero(&self) -> bool { !self.data.is_empty() } fn is_positive(&self) -> bool { self.is_not_zero() } fn is_negative(&self) -> bool { false } fn is_nonpositive(&self) -> bool { self.is_zero() } fn is_nonnegative(&self) -> bool { true } fn to_uint(&self) -> uint { match self.data.len() { 0 => 0, 1 => self.data[0] as uint, 2 => BigDigit::to_uint(self.data[1], self.data[0]), _ => uint::max_value } } fn to_str_radix(&self, radix: uint) -> ~str { fail_unless!(1 < radix && radix <= 16); let (base, max_len) = get_radix_base(radix); if base == BigDigit::base { return fill_concat(self.data, radix, max_len) } return fill_concat(convert_base(copy *self, base), radix, max_len); fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] { let divider = BigUint::from_uint(base); let mut result = ~[]; let mut r = n; while r > divider { let (d, r0) = r.divmod(÷r); result += [r0.to_uint() as BigDigit]; r = d; } if r.is_not_zero() { result += [r.to_uint() as BigDigit]; } return result; } fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str { if v.is_empty() { return ~"0" } let s = str::concat(vec::reversed(v).map(|n| { let s = uint::to_str_radix(*n as uint, radix); str::from_chars(vec::from_elem(l - s.len(), '0')) + s })); str::trim_left_chars(s, ['0']).to_owned() } } priv fn shl_unit(self, n_unit: uint) -> BigUint { if n_unit == 0 || self.is_zero() { return self; } return BigUint::new(vec::from_elem(n_unit, 0) + self.data); } priv fn shl_bits(self, n_bits: uint) -> BigUint { if n_bits == 0 || self.is_zero() { return self; } let mut carry = 0; let shifted = do vec::map(self.data) |elem| { let (hi, lo) = BigDigit::from_uint( (*elem as uint) << n_bits | (carry as uint) ); carry = hi; lo }; if carry == 0 { return BigUint::new(shifted); } return BigUint::new(shifted + [carry]); } priv fn shr_unit(self, n_unit: uint) -> BigUint { if n_unit == 0 { return self; } if self.data.len() < n_unit { return Zero::zero(); } return BigUint::from_slice( vec::slice(self.data, n_unit, self.data.len()) ); } priv fn shr_bits(self, n_bits: uint) -> BigUint { if n_bits == 0 || self.data.is_empty() { return self; } let mut borrow = 0; let mut shifted = ~[]; for self.data.each_reverse |elem| { shifted = ~[(*elem >> n_bits) | borrow] + shifted; borrow = *elem << (uint::bits - n_bits); } return BigUint::new(shifted); } } #[cfg(target_arch = "x86_64")] priv fn get_radix_base(radix: uint) -> (uint, uint) { fail_unless!(1 < radix && radix <= 16); match radix { 2 => (4294967296, 32), 3 => (3486784401, 20), 4 => (4294967296, 16), 5 => (1220703125, 13), 6 => (2176782336, 12), 7 => (1977326743, 11), 8 => (1073741824, 10), 9 => (3486784401, 10), 10 => (1000000000, 9), 11 => (2357947691, 9), 12 => (429981696, 8), 13 => (815730721, 8), 14 => (1475789056, 8), 15 => (2562890625, 8), 16 => (4294967296, 8), _ => fail!() } } #[cfg(target_arch = "arm")] #[cfg(target_arch = "x86")] #[cfg(target_arch = "mips")] priv fn get_radix_base(radix: uint) -> (uint, uint) { fail_unless!(1 < radix && radix <= 16); match radix { 2 => (65536, 16), 3 => (59049, 10), 4 => (65536, 8), 5 => (15625, 6), 6 => (46656, 6), 7 => (16807, 5), 8 => (32768, 5), 9 => (59049, 5), 10 => (10000, 4), 11 => (14641, 4), 12 => (20736, 4), 13 => (28561, 4), 14 => (38416, 4), 15 => (50625, 4), 16 => (65536, 4), _ => fail!() } } /// A Sign is a BigInt's composing element. #[deriving(Eq)] pub enum Sign { Minus, Zero, Plus } impl Ord for Sign { fn lt(&self, other: &Sign) -> bool { self.cmp(other) < 0 } fn le(&self, other: &Sign) -> bool { self.cmp(other) <= 0 } fn ge(&self, other: &Sign) -> bool { self.cmp(other) >= 0 } fn gt(&self, other: &Sign) -> bool { self.cmp(other) > 0 } } pub impl Sign { /// Compare two Sign. fn cmp(&self, other: &Sign) -> int { match (*self, *other) { (Minus, Minus) | (Zero, Zero) | (Plus, Plus) => 0, (Minus, Zero) | (Minus, Plus) | (Zero, Plus) => -1, _ => 1 } } /// Negate Sign value. fn neg(&self) -> Sign { match *self { Minus => Plus, Zero => Zero, Plus => Minus } } } /// A big signed integer type. pub struct BigInt { priv sign: Sign, priv data: BigUint } impl Eq for BigInt { fn eq(&self, other: &BigInt) -> bool { self.cmp(other) == 0 } fn ne(&self, other: &BigInt) -> bool { self.cmp(other) != 0 } } impl Ord for BigInt { fn lt(&self, other: &BigInt) -> bool { self.cmp(other) < 0 } fn le(&self, other: &BigInt) -> bool { self.cmp(other) <= 0 } fn ge(&self, other: &BigInt) -> bool { self.cmp(other) >= 0 } fn gt(&self, other: &BigInt) -> bool { self.cmp(other) > 0 } } impl ToStr for BigInt { fn to_str(&self) -> ~str { self.to_str_radix(10) } } impl from_str::FromStr for BigInt { fn from_str(s: &str) -> Option { BigInt::from_str_radix(s, 10) } } impl Shl for BigInt { fn shl(&self, rhs: &uint) -> BigInt { BigInt::from_biguint(self.sign, self.data << *rhs) } } impl Shr for BigInt { fn shr(&self, rhs: &uint) -> BigInt { BigInt::from_biguint(self.sign, self.data >> *rhs) } } impl Zero for BigInt { pub fn zero() -> BigInt { BigInt::from_biguint(Zero, Zero::zero()) } } impl One for BigInt { pub fn one() -> BigInt { BigInt::from_biguint(Plus, One::one()) } } impl Add for BigInt { fn add(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => copy *other, (_, Zero) => copy *self, (Plus, Plus) => BigInt::from_biguint(Plus, self.data + other.data), (Plus, Minus) => self - (-*other), (Minus, Plus) => other - (-*self), (Minus, Minus) => -((-self) + (-*other)) } } } impl Sub for BigInt { fn sub(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => -other, (_, Zero) => copy *self, (Plus, Plus) => match self.data.cmp(&other.data) { s if s < 0 => BigInt::from_biguint(Minus, other.data - self.data), s if s > 0 => BigInt::from_biguint(Plus, self.data - other.data), _ => Zero::zero() }, (Plus, Minus) => self + (-*other), (Minus, Plus) => -((-self) + *other), (Minus, Minus) => (-other) - (-*self) } } } impl Mul for BigInt { fn mul(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) | (_, Zero) => Zero::zero(), (Plus, Plus) | (Minus, Minus) => { BigInt::from_biguint(Plus, self.data * other.data) }, (Plus, Minus) | (Minus, Plus) => { BigInt::from_biguint(Minus, self.data * other.data) } } } } impl Div for BigInt { fn div(&self, other: &BigInt) -> BigInt { let (d, _) = self.divmod(other); return d; } } impl Modulo for BigInt { fn modulo(&self, other: &BigInt) -> BigInt { let (_, m) = self.divmod(other); return m; } } impl Neg for BigInt { fn neg(&self) -> BigInt { BigInt::from_biguint(self.sign.neg(), copy self.data) } } impl IntConvertible for BigInt { fn to_int(&self) -> int { match self.sign { Plus => uint::min(self.to_uint(), int::max_value as uint) as int, Zero => 0, Minus => uint::min((-self).to_uint(), (int::max_value as uint) + 1) as int } } fn from_int(n: int) -> BigInt { if n > 0 { return BigInt::from_biguint(Plus, BigUint::from_uint(n as uint)); } if n < 0 { return BigInt::from_biguint( Minus, BigUint::from_uint(uint::max_value - (n as uint) + 1) ); } return Zero::zero(); } } pub impl BigInt { /// Creates and initializes an BigInt. pub fn new(sign: Sign, v: ~[BigDigit]) -> BigInt { BigInt::from_biguint(sign, BigUint::new(v)) } /// Creates and initializes an BigInt. pub fn from_biguint(sign: Sign, data: BigUint) -> BigInt { if sign == Zero || data.is_zero() { return BigInt { sign: Zero, data: Zero::zero() }; } return BigInt { sign: sign, data: data }; } /// Creates and initializes an BigInt. pub fn from_uint(n: uint) -> BigInt { if n == 0 { return Zero::zero(); } return BigInt::from_biguint(Plus, BigUint::from_uint(n)); } /// Creates and initializes an BigInt. pub fn from_slice(sign: Sign, slice: &[BigDigit]) -> BigInt { BigInt::from_biguint(sign, BigUint::from_slice(slice)) } /// Creates and initializes an BigInt. pub fn from_str_radix(s: &str, radix: uint) -> Option { BigInt::parse_bytes(str::to_bytes(s), radix) } /// Creates and initializes an BigInt. pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { if buf.is_empty() { return None; } let mut sign = Plus; let mut start = 0; if buf[0] == ('-' as u8) { sign = Minus; start = 1; } return BigUint::parse_bytes(vec::slice(buf, start, buf.len()), radix) .map(|bu| BigInt::from_biguint(sign, *bu)); } fn abs(&self) -> BigInt { BigInt::from_biguint(Plus, copy self.data) } fn cmp(&self, other: &BigInt) -> int { let ss = self.sign, os = other.sign; if ss < os { return -1; } if ss > os { return 1; } fail_unless!(ss == os); match ss { Zero => 0, Plus => self.data.cmp(&other.data), Minus => self.data.cmp(&other.data).neg(), } } fn divmod(&self, other: &BigInt) -> (BigInt, BigInt) { // m.sign == other.sign let (d_ui, m_ui) = self.data.divmod(&other.data); let d = BigInt::from_biguint(Plus, d_ui), m = BigInt::from_biguint(Plus, m_ui); match (self.sign, other.sign) { (_, Zero) => fail!(), (Plus, Plus) | (Zero, Plus) => (d, m), (Plus, Minus) | (Zero, Minus) => if m.is_zero() { (-d, Zero::zero()) } else { (-d - One::one(), m + *other) }, (Minus, Plus) => if m.is_zero() { (-d, Zero::zero()) } else { (-d - One::one(), other - m) }, (Minus, Minus) => (d, -m) } } fn quot(&self, other: &BigInt) -> BigInt { let (q, _) = self.quotrem(other); return q; } fn rem(&self, other: &BigInt) -> BigInt { let (_, r) = self.quotrem(other); return r; } fn quotrem(&self, other: &BigInt) -> (BigInt, BigInt) { // r.sign == self.sign let (q_ui, r_ui) = self.data.quotrem(&other.data); let q = BigInt::from_biguint(Plus, q_ui); let r = BigInt::from_biguint(Plus, r_ui); match (self.sign, other.sign) { (_, Zero) => fail!(), (Plus, Plus) | (Zero, Plus) => ( q, r), (Plus, Minus) | (Zero, Minus) => (-q, r), (Minus, Plus) => (-q, -r), (Minus, Minus) => ( q, -r) } } fn is_zero(&self) -> bool { self.sign == Zero } fn is_not_zero(&self) -> bool { self.sign != Zero } fn is_positive(&self) -> bool { self.sign == Plus } fn is_negative(&self) -> bool { self.sign == Minus } fn is_nonpositive(&self) -> bool { self.sign != Plus } fn is_nonnegative(&self) -> bool { self.sign != Minus } fn to_uint(&self) -> uint { match self.sign { Plus => self.data.to_uint(), Zero => 0, Minus => 0 } } fn to_str_radix(&self, radix: uint) -> ~str { match self.sign { Plus => self.data.to_str_radix(radix), Zero => ~"0", Minus => ~"-" + self.data.to_str_radix(radix) } } } #[cfg(test)] mod biguint_tests { use core::*; use core::num::{IntConvertible, Zero, One}; use super::{BigUint, BigDigit}; #[test] fn test_from_slice() { fn check(slice: &[BigDigit], data: &[BigDigit]) { fail_unless!(data == BigUint::from_slice(slice).data); } check(~[1], ~[1]); check(~[0, 0, 0], ~[]); check(~[1, 2, 0, 0], ~[1, 2]); check(~[0, 0, 1, 2], ~[0, 0, 1, 2]); check(~[0, 0, 1, 2, 0, 0], ~[0, 0, 1, 2]); check(~[-1], ~[-1]); } #[test] fn test_cmp() { let data = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ] .map(|v| BigUint::from_slice(*v)); for data.eachi |i, ni| { for vec::slice(data, i, data.len()).eachi |j0, nj| { let j = j0 + i; if i == j { fail_unless!(ni.cmp(nj) == 0); fail_unless!(nj.cmp(ni) == 0); fail_unless!(ni == nj); fail_unless!(!(ni != nj)); fail_unless!(ni <= nj); fail_unless!(ni >= nj); fail_unless!(!(ni < nj)); fail_unless!(!(ni > nj)); } else { fail_unless!(ni.cmp(nj) < 0); fail_unless!(nj.cmp(ni) > 0); fail_unless!(!(ni == nj)); fail_unless!(ni != nj); fail_unless!(ni <= nj); fail_unless!(!(ni >= nj)); fail_unless!(ni < nj); fail_unless!(!(ni > nj)); fail_unless!(!(nj <= ni)); fail_unless!(nj >= ni); fail_unless!(!(nj < ni)); fail_unless!(nj > ni); } } } } #[test] fn test_shl() { fn check(v: ~[BigDigit], shift: uint, ans: ~[BigDigit]) { fail_unless!(BigUint::new(v) << shift == BigUint::new(ans)); } check(~[], 3, ~[]); check(~[1, 1, 1], 3, ~[1 << 3, 1 << 3, 1 << 3]); check(~[1 << (BigDigit::bits - 2)], 2, ~[0, 1]); check(~[1 << (BigDigit::bits - 2)], 3, ~[0, 2]); check(~[1 << (BigDigit::bits - 2)], 3 + BigDigit::bits, ~[0, 0, 2]); test_shl_bits(); #[cfg(target_arch = "x86_64")] fn test_shl_bits() { check(~[0x7654_3210, 0xfedc_ba98, 0x7654_3210, 0xfedc_ba98], 4, ~[0x6543_2100, 0xedcb_a987, 0x6543_210f, 0xedcb_a987, 0xf]); check(~[0x2222_1111, 0x4444_3333, 0x6666_5555, 0x8888_7777], 16, ~[0x1111_0000, 0x3333_2222, 0x5555_4444, 0x7777_6666, 0x8888]); } #[cfg(target_arch = "arm")] #[cfg(target_arch = "x86")] #[cfg(target_arch = "mips")] fn test_shl_bits() { check(~[0x3210, 0x7654, 0xba98, 0xfedc, 0x3210, 0x7654, 0xba98, 0xfedc], 4, ~[0x2100, 0x6543, 0xa987, 0xedcb, 0x210f, 0x6543, 0xa987, 0xedcb, 0xf]); check(~[0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888], 16, ~[0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888]); } } #[test] #[ignore(cfg(target_arch = "x86"))] #[ignore(cfg(target_arch = "arm"))] #[ignore(cfg(target_arch = "mips"))] fn test_shr() { fn check(v: ~[BigDigit], shift: uint, ans: ~[BigDigit]) { fail_unless!(BigUint::new(v) >> shift == BigUint::new(ans)); } check(~[], 3, ~[]); check(~[1, 1, 1], 3, ~[1 << (BigDigit::bits - 3), 1 << (BigDigit::bits - 3)]); check(~[1 << 2], 2, ~[1]); check(~[1, 2], 3, ~[1 << (BigDigit::bits - 2)]); check(~[1, 1, 2], 3 + BigDigit::bits, ~[1 << (BigDigit::bits - 2)]); test_shr_bits(); #[cfg(target_arch = "x86_64")] fn test_shr_bits() { check(~[0x6543_2100, 0xedcb_a987, 0x6543_210f, 0xedcb_a987, 0xf], 4, ~[0x7654_3210, 0xfedc_ba98, 0x7654_3210, 0xfedc_ba98]); check(~[0x1111_0000, 0x3333_2222, 0x5555_4444, 0x7777_6666, 0x8888], 16, ~[0x2222_1111, 0x4444_3333, 0x6666_5555, 0x8888_7777]); } #[cfg(target_arch = "arm")] #[cfg(target_arch = "x86")] #[cfg(target_arch = "mips")] fn test_shr_bits() { check(~[0x2100, 0x6543, 0xa987, 0xedcb, 0x210f, 0x6543, 0xa987, 0xedcb, 0xf], 4, ~[0x3210, 0x7654, 0xba98, 0xfedc, 0x3210, 0x7654, 0xba98, 0xfedc]); check(~[0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888], 16, ~[0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888]); } } #[test] fn test_convert_int() { fn check(v: ~[BigDigit], i: int) { let b = BigUint::new(v); fail_unless!(b == IntConvertible::from_int(i)); fail_unless!(b.to_int() == i); } check(~[], 0); check(~[1], 1); check(~[-1], (uint::max_value >> BigDigit::bits) as int); check(~[ 0, 1], ((uint::max_value >> BigDigit::bits) + 1) as int); check(~[-1, -1 >> 1], int::max_value); fail_unless!(BigUint::new(~[0, -1]).to_int() == int::max_value); fail_unless!(BigUint::new(~[0, 0, 1]).to_int() == int::max_value); fail_unless!(BigUint::new(~[0, 0, -1]).to_int() == int::max_value); } #[test] fn test_convert_uint() { fn check(v: ~[BigDigit], u: uint) { let b = BigUint::new(v); fail_unless!(b == BigUint::from_uint(u)); fail_unless!(b.to_uint() == u); } check(~[], 0); check(~[ 1], 1); check(~[-1], uint::max_value >> BigDigit::bits); check(~[ 0, 1], (uint::max_value >> BigDigit::bits) + 1); check(~[ 0, -1], uint::max_value << BigDigit::bits); check(~[-1, -1], uint::max_value); fail_unless!(BigUint::new(~[0, 0, 1]).to_uint() == uint::max_value); fail_unless!(BigUint::new(~[0, 0, -1]).to_uint() == uint::max_value); } static sum_triples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[ (&[], &[], &[]), (&[], &[ 1], &[ 1]), (&[ 1], &[ 1], &[ 2]), (&[ 1], &[ 1, 1], &[ 2, 1]), (&[ 1], &[-1], &[ 0, 1]), (&[ 1], &[-1, -1], &[ 0, 0, 1]), (&[-1, -1], &[-1, -1], &[-2, -1, 1]), (&[ 1, 1, 1], &[-1, -1], &[ 0, 1, 2]), (&[ 2, 2, 1], &[-1, -2], &[ 1, 1, 2]) ]; #[test] fn test_add() { for sum_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); fail_unless!(a + b == c); fail_unless!(b + a == c); } } #[test] fn test_sub() { for sum_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); fail_unless!(c - a == b); fail_unless!(c - b == a); } } static mul_triples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[ (&[], &[], &[]), (&[], &[ 1], &[]), (&[ 2], &[], &[]), (&[ 1], &[ 1], &[1]), (&[ 2], &[ 3], &[ 6]), (&[ 1], &[ 1, 1, 1], &[1, 1, 1]), (&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]), (&[ 1, 1, 1], &[-1], &[-1, -1, -1]), (&[ 1, 2, 3], &[-1], &[-1, -2, -2, 2]), (&[ 1, 2, 3, 4], &[-1], &[-1, -2, -2, -2, 3]), (&[-1], &[-1], &[ 1, -2]), (&[-1, -1], &[-1], &[ 1, -1, -2]), (&[-1, -1, -1], &[-1], &[ 1, -1, -1, -2]), (&[-1, -1, -1, -1], &[-1], &[ 1, -1, -1, -1, -2]), (&[-1/2 + 1], &[ 2], &[ 0, 1]), (&[0, -1/2 + 1], &[ 2], &[ 0, 0, 1]), (&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]), (&[-1, -1], &[-1, -1, -1], &[1, 0, -1, -2, -1]), (&[-1, -1, -1], &[-1, -1, -1, -1], &[1, 0, 0, -1, -2, -1, -1]), (&[ 0, 0, 1], &[ 1, 2, 3], &[0, 0, 1, 2, 3]), (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; static divmod_quadruples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[ (&[ 1], &[ 2], &[], &[1]), (&[ 1, 1], &[ 2], &[-1/2+1], &[1]), (&[ 1, 1, 1], &[ 2], &[-1/2+1, -1/2+1], &[1]), (&[ 0, 1], &[-1], &[1], &[1]), (&[-1, -1], &[-2], &[2, 1], &[3]) ]; #[test] fn test_mul() { for mul_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); fail_unless!(a * b == c); fail_unless!(b * a == c); } for divmod_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); let d = BigUint::from_slice(dVec); fail_unless!(a == b * c + d); fail_unless!(a == c * b + d); } } #[test] fn test_divmod() { for mul_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); if a.is_not_zero() { fail_unless!(c.divmod(&a) == (b, Zero::zero())); } if b.is_not_zero() { fail_unless!(c.divmod(&b) == (a, Zero::zero())); } } for divmod_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); let d = BigUint::from_slice(dVec); if b.is_not_zero() { fail_unless!(a.divmod(&b) == (c, d)); } } } fn to_str_pairs() -> ~[ (BigUint, ~[(uint, ~str)]) ] { let bits = BigDigit::bits; ~[( Zero::zero(), ~[ (2, ~"0"), (3, ~"0") ]), ( BigUint::from_slice([ 0xff ]), ~[ (2, ~"11111111"), (3, ~"100110"), (4, ~"3333"), (5, ~"2010"), (6, ~"1103"), (7, ~"513"), (8, ~"377"), (9, ~"313"), (10, ~"255"), (11, ~"212"), (12, ~"193"), (13, ~"168"), (14, ~"143"), (15, ~"120"), (16, ~"ff") ]), ( BigUint::from_slice([ 0xfff ]), ~[ (2, ~"111111111111"), (4, ~"333333"), (16, ~"fff") ]), ( BigUint::from_slice([ 1, 2 ]), ~[ (2, ~"10" + str::from_chars(vec::from_elem(bits - 1, '0')) + "1"), (4, ~"2" + str::from_chars(vec::from_elem(bits / 2 - 1, '0')) + "1"), (10, match bits { 32 => ~"8589934593", 16 => ~"131073", _ => fail!() }), (16, ~"2" + str::from_chars(vec::from_elem(bits / 4 - 1, '0')) + "1") ]), ( BigUint::from_slice([ 1, 2, 3 ]), ~[ (2, ~"11" + str::from_chars(vec::from_elem(bits - 2, '0')) + "10" + str::from_chars(vec::from_elem(bits - 1, '0')) + "1"), (4, ~"3" + str::from_chars(vec::from_elem(bits / 2 - 1, '0')) + "2" + str::from_chars(vec::from_elem(bits / 2 - 1, '0')) + "1"), (10, match bits { 32 => ~"55340232229718589441", 16 => ~"12885032961", _ => fail!() }), (16, ~"3" + str::from_chars(vec::from_elem(bits / 4 - 1, '0')) + "2" + str::from_chars(vec::from_elem(bits / 4 - 1, '0')) + "1") ]) ] } #[test] fn test_to_str_radix() { for to_str_pairs().each |num_pair| { let &(n, rs) = num_pair; for rs.each |str_pair| { let &(radix, str) = str_pair; fail_unless!(n.to_str_radix(radix) == str); } } } #[test] fn test_from_str_radix() { for to_str_pairs().each |num_pair| { let &(n, rs) = num_pair; for rs.each |str_pair| { let &(radix, str) = str_pair; fail_unless!(Some(n) == BigUint::from_str_radix(str, radix)); } } fail_unless!(BigUint::from_str_radix(~"Z", 10) == None); fail_unless!(BigUint::from_str_radix(~"_", 2) == None); fail_unless!(BigUint::from_str_radix(~"-1", 10) == None); } #[test] fn test_factor() { fn factor(n: uint) -> BigUint { let mut f= One::one::(); for uint::range(2, n + 1) |i| { f *= BigUint::from_uint(i); } return f; } fn check(n: uint, s: &str) { let n = factor(n); let ans = match BigUint::from_str_radix(s, 10) { Some(x) => x, None => fail!() }; fail_unless!(n == ans); } check(3, "6"); check(10, "3628800"); check(20, "2432902008176640000"); check(30, "265252859812191058636308480000000"); } } #[cfg(test)] mod bigint_tests { use super::{BigInt, BigUint, BigDigit, Sign, Minus, Zero, Plus}; use core::*; use core::num::{IntConvertible, Zero, One}; #[test] fn test_from_biguint() { fn check(inp_s: Sign, inp_n: uint, ans_s: Sign, ans_n: uint) { let inp = BigInt::from_biguint(inp_s, BigUint::from_uint(inp_n)); let ans = BigInt { sign: ans_s, data: BigUint::from_uint(ans_n)}; fail_unless!(inp == ans); } check(Plus, 1, Plus, 1); check(Plus, 0, Zero, 0); check(Minus, 1, Minus, 1); check(Zero, 1, Zero, 0); } #[test] fn test_cmp() { let vs = [ &[2], &[1, 1], &[2, 1], &[1, 1, 1] ]; let mut nums = vec::reversed(vs) .map(|s| BigInt::from_slice(Minus, *s)); nums.push(Zero::zero()); nums.push_all_move(vs.map(|s| BigInt::from_slice(Plus, *s))); for nums.eachi |i, ni| { for vec::slice(nums, i, nums.len()).eachi |j0, nj| { let j = i + j0; if i == j { fail_unless!(ni.cmp(nj) == 0); fail_unless!(nj.cmp(ni) == 0); fail_unless!(ni == nj); fail_unless!(!(ni != nj)); fail_unless!(ni <= nj); fail_unless!(ni >= nj); fail_unless!(!(ni < nj)); fail_unless!(!(ni > nj)); } else { fail_unless!(ni.cmp(nj) < 0); fail_unless!(nj.cmp(ni) > 0); fail_unless!(!(ni == nj)); fail_unless!(ni != nj); fail_unless!(ni <= nj); fail_unless!(!(ni >= nj)); fail_unless!(ni < nj); fail_unless!(!(ni > nj)); fail_unless!(!(nj <= ni)); fail_unless!(nj >= ni); fail_unless!(!(nj < ni)); fail_unless!(nj > ni); } } } } #[test] fn test_convert_int() { fn check(b: BigInt, i: int) { fail_unless!(b == IntConvertible::from_int(i)); fail_unless!(b.to_int() == i); } check(Zero::zero(), 0); check(One::one(), 1); check(BigInt::from_biguint( Plus, BigUint::from_uint(int::max_value as uint) ), int::max_value); fail_unless!(BigInt::from_biguint( Plus, BigUint::from_uint(int::max_value as uint + 1) ).to_int() == int::max_value); fail_unless!(BigInt::from_biguint( Plus, BigUint::new(~[1, 2, 3]) ).to_int() == int::max_value); check(BigInt::from_biguint( Minus, BigUint::from_uint(-int::min_value as uint) ), int::min_value); fail_unless!(BigInt::from_biguint( Minus, BigUint::from_uint(-int::min_value as uint + 1) ).to_int() == int::min_value); fail_unless!(BigInt::from_biguint( Minus, BigUint::new(~[1, 2, 3]) ).to_int() == int::min_value); } #[test] fn test_convert_uint() { fn check(b: BigInt, u: uint) { fail_unless!(b == BigInt::from_uint(u)); fail_unless!(b.to_uint() == u); } check(Zero::zero(), 0); check(One::one(), 1); check( BigInt::from_biguint(Plus, BigUint::from_uint(uint::max_value)), uint::max_value); fail_unless!(BigInt::from_biguint( Plus, BigUint::new(~[1, 2, 3]) ).to_uint() == uint::max_value); fail_unless!(BigInt::from_biguint( Minus, BigUint::from_uint(uint::max_value) ).to_uint() == 0); fail_unless!(BigInt::from_biguint( Minus, BigUint::new(~[1, 2, 3]) ).to_uint() == 0); } static sum_triples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[ (&[], &[], &[]), (&[], &[ 1], &[ 1]), (&[ 1], &[ 1], &[ 2]), (&[ 1], &[ 1, 1], &[ 2, 1]), (&[ 1], &[-1], &[ 0, 1]), (&[ 1], &[-1, -1], &[ 0, 0, 1]), (&[-1, -1], &[-1, -1], &[-2, -1, 1]), (&[ 1, 1, 1], &[-1, -1], &[ 0, 1, 2]), (&[ 2, 2, 1], &[-1, -2], &[ 1, 1, 2]) ]; #[test] fn test_add() { for sum_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); fail_unless!(a + b == c); fail_unless!(b + a == c); fail_unless!(c + (-a) == b); fail_unless!(c + (-b) == a); fail_unless!(a + (-c) == (-b)); fail_unless!(b + (-c) == (-a)); fail_unless!((-a) + (-b) == (-c)); fail_unless!(a + (-a) == Zero::zero()); } } #[test] fn test_sub() { for sum_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); fail_unless!(c - a == b); fail_unless!(c - b == a); fail_unless!((-b) - a == (-c)); fail_unless!((-a) - b == (-c)); fail_unless!(b - (-a) == c); fail_unless!(a - (-b) == c); fail_unless!((-c) - (-a) == (-b)); fail_unless!(a - a == Zero::zero()); } } static mul_triples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[ (&[], &[], &[]), (&[], &[ 1], &[]), (&[ 2], &[], &[]), (&[ 1], &[ 1], &[1]), (&[ 2], &[ 3], &[ 6]), (&[ 1], &[ 1, 1, 1], &[1, 1, 1]), (&[ 1, 2, 3], &[ 3], &[ 3, 6, 9]), (&[ 1, 1, 1], &[-1], &[-1, -1, -1]), (&[ 1, 2, 3], &[-1], &[-1, -2, -2, 2]), (&[ 1, 2, 3, 4], &[-1], &[-1, -2, -2, -2, 3]), (&[-1], &[-1], &[ 1, -2]), (&[-1, -1], &[-1], &[ 1, -1, -2]), (&[-1, -1, -1], &[-1], &[ 1, -1, -1, -2]), (&[-1, -1, -1, -1], &[-1], &[ 1, -1, -1, -1, -2]), (&[-1/2 + 1], &[ 2], &[ 0, 1]), (&[0, -1/2 + 1], &[ 2], &[ 0, 0, 1]), (&[ 1, 2], &[ 1, 2, 3], &[1, 4, 7, 6]), (&[-1, -1], &[-1, -1, -1], &[1, 0, -1, -2, -1]), (&[-1, -1, -1], &[-1, -1, -1, -1], &[1, 0, 0, -1, -2, -1, -1]), (&[ 0, 0, 1], &[ 1, 2, 3], &[0, 0, 1, 2, 3]), (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; static divmod_quadruples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[ (&[ 1], &[ 2], &[], &[1]), (&[ 1, 1], &[ 2], &[-1/2+1], &[1]), (&[ 1, 1, 1], &[ 2], &[-1/2+1, -1/2+1], &[1]), (&[ 0, 1], &[-1], &[1], &[1]), (&[-1, -1], &[-2], &[2, 1], &[3]) ]; #[test] fn test_mul() { for mul_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); fail_unless!(a * b == c); fail_unless!(b * a == c); fail_unless!((-a) * b == -c); fail_unless!((-b) * a == -c); } for divmod_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); let d = BigInt::from_slice(Plus, dVec); fail_unless!(a == b * c + d); fail_unless!(a == c * b + d); } } #[test] fn test_divmod() { fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) { let (d, m) = a.divmod(b); if m.is_not_zero() { fail_unless!(m.sign == b.sign); } fail_unless!(m.abs() <= b.abs()); fail_unless!(*a == b * d + m); fail_unless!(d == *ans_d); fail_unless!(m == *ans_m); } fn check(a: &BigInt, b: &BigInt, d: &BigInt, m: &BigInt) { if m.is_zero() { check_sub(a, b, d, m); check_sub(a, &b.neg(), &d.neg(), m); check_sub(&a.neg(), b, &d.neg(), m); check_sub(&a.neg(), &b.neg(), d, m); } else { check_sub(a, b, d, m); check_sub(a, &b.neg(), &(d.neg() - One::one()), &(m - *b)); check_sub(&a.neg(), b, &(d.neg() - One::one()), &(b - *m)); check_sub(&a.neg(), &b.neg(), d, &m.neg()); } } for mul_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); if a.is_not_zero() { check(&c, &a, &b, &Zero::zero()); } if b.is_not_zero() { check(&c, &b, &a, &Zero::zero()); } } for divmod_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); let d = BigInt::from_slice(Plus, dVec); if b.is_not_zero() { check(&a, &b, &c, &d); } } } #[test] fn test_quotrem() { fn check_sub(a: &BigInt, b: &BigInt, ans_q: &BigInt, ans_r: &BigInt) { let (q, r) = a.quotrem(b); if r.is_not_zero() { fail_unless!(r.sign == a.sign); } fail_unless!(r.abs() <= b.abs()); fail_unless!(*a == b * q + r); fail_unless!(q == *ans_q); fail_unless!(r == *ans_r); } fn check(a: &BigInt, b: &BigInt, q: &BigInt, r: &BigInt) { check_sub(a, b, q, r); check_sub(a, &b.neg(), &q.neg(), r); check_sub(&a.neg(), b, &q.neg(), &r.neg()); check_sub(&a.neg(), &b.neg(), q, &r.neg()); } for mul_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); if a.is_not_zero() { check(&c, &a, &b, &Zero::zero()); } if b.is_not_zero() { check(&c, &b, &a, &Zero::zero()); } } for divmod_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); let c = BigInt::from_slice(Plus, cVec); let d = BigInt::from_slice(Plus, dVec); if b.is_not_zero() { check(&a, &b, &c, &d); } } } #[test] fn test_to_str_radix() { fn check(n: int, ans: &str) { fail_unless!(ans == IntConvertible::from_int::( n).to_str_radix(10)); } check(10, "10"); check(1, "1"); check(0, "0"); check(-1, "-1"); check(-10, "-10"); } #[test] fn test_from_str_radix() { fn check(s: &str, ans: Option) { let ans = ans.map(|&n| IntConvertible::from_int(n)); fail_unless!(BigInt::from_str_radix(s, 10) == ans); } check("10", Some(10)); check("1", Some(1)); check("0", Some(0)); check("-1", Some(-1)); check("-10", Some(-10)); check("Z", None); check("_", None); } #[test] fn test_neg() { fail_unless!(-BigInt::new(Plus, ~[1, 1, 1]) == BigInt::new(Minus, ~[1, 1, 1])); fail_unless!(-BigInt::new(Minus, ~[1, 1, 1]) == BigInt::new(Plus, ~[1, 1, 1])); fail_unless!(-Zero::zero::() == Zero::zero::()); } }