auto merge of #9014 : dcrewi/rust/convert-between-bigints, r=anasazi

This commit is contained in:
bors 2013-09-11 16:46:00 -07:00
commit 91ab8a3f52

View File

@ -503,7 +503,7 @@ fn is_odd(&self) -> bool { !self.is_even() }
impl IntConvertible for BigUint {
#[inline]
fn to_int(&self) -> int {
num::min(self.to_uint(), int::max_value as uint) as int
self.to_int_opt().expect("BigUint conversion would overflow int")
}
#[inline]
@ -615,18 +615,43 @@ pub fn parse_bytes(buf: &[u8], radix: uint)
}
/// Converts this big integer into a uint, returning the uint::max_value if
/// it's too large to fit in a uint.
/// Converts this BigUint into a uint, failing if the conversion
/// would overflow.
#[inline]
pub fn to_uint(&self) -> uint {
self.to_uint_opt().expect("BigUint conversion would overflow uint")
}
/// Converts this BigUint into a uint, unless it would overflow.
#[inline]
pub fn to_uint_opt(&self) -> Option<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
0 => Some(0),
1 => Some(self.data[0] as uint),
2 => Some(BigDigit::to_uint(self.data[1], self.data[0])),
_ => None
}
}
// Converts this BigUint into an int, unless it would overflow.
pub fn to_int_opt(&self) -> Option<int> {
self.to_uint_opt().chain(|n| {
// If top bit of uint is set, it's too large to convert to
// int.
if (n >> (2*BigDigit::bits - 1) != 0) {
None
} else {
Some(n as int)
}
})
}
/// Converts this BigUint into a BigInt.
#[inline]
pub fn to_bigint(&self) -> BigInt {
BigInt::from_biguint(Plus, self.clone())
}
#[inline]
fn shl_unit(&self, n_unit: uint) -> BigUint {
if n_unit == 0 || self.is_zero() { return (*self).clone(); }
@ -1048,12 +1073,7 @@ fn is_odd(&self) -> bool { self.data.is_odd() }
impl IntConvertible for BigInt {
#[inline]
fn to_int(&self) -> int {
match self.sign {
Plus => num::min(self.to_uint(), int::max_value as uint) as int,
Zero => 0,
Minus => num::min((-self).to_uint(),
(int::max_value as uint) + 1) as int
}
self.to_int_opt().expect("BigInt conversion would overflow int")
}
#[inline]
@ -1179,12 +1199,55 @@ pub fn parse_bytes(buf: &[u8], radix: uint)
.map_move(|bu| BigInt::from_biguint(sign, bu));
}
/// Converts this BigInt into a uint, failing if the conversion
/// would overflow.
#[inline]
pub fn to_uint(&self) -> uint {
self.to_uint_opt().expect("BigInt conversion would overflow uint")
}
/// Converts this BigInt into a uint, unless it would overflow.
#[inline]
pub fn to_uint_opt(&self) -> Option<uint> {
match self.sign {
Plus => self.data.to_uint(),
Zero => 0,
Minus => 0
Plus => self.data.to_uint_opt(),
Zero => Some(0),
Minus => None
}
}
/// Converts this BigInt into an int, unless it would overflow.
pub fn to_int_opt(&self) -> Option<int> {
match self.sign {
Plus => self.data.to_int_opt(),
Zero => Some(0),
Minus => self.data.to_uint_opt().chain(|n| {
let m: uint = 1 << (2*BigDigit::bits-1);
if (n > m) {
None
} else if (n == m) {
Some(int::min_value)
} else {
Some(-(n as int))
}
})
}
}
/// Converts this BigInt into a BigUint, failing if BigInt is
/// negative.
#[inline]
pub fn to_biguint(&self) -> BigUint {
self.to_biguint_opt().expect("negative BigInt cannot convert to BigUint")
}
/// Converts this BigInt into a BigUint, if it's not negative.
#[inline]
pub fn to_biguint_opt(&self) -> Option<BigUint> {
match self.sign {
Plus => Some(self.data.clone()),
Zero => Some(Zero::zero()),
Minus => None
}
}
}
@ -1385,9 +1448,9 @@ fn check(v: ~[BigDigit], i: int) {
check(~[ 0, 1], ((uint::max_value >> BigDigit::bits) + 1) as int);
check(~[-1, -1 >> 1], int::max_value);
assert_eq!(BigUint::new(~[0, -1]).to_int(), int::max_value);
assert_eq!(BigUint::new(~[0, 0, 1]).to_int(), int::max_value);
assert_eq!(BigUint::new(~[0, 0, -1]).to_int(), int::max_value);
assert_eq!(BigUint::new(~[0, -1]).to_int_opt(), None);
assert_eq!(BigUint::new(~[0, 0, 1]).to_int_opt(), None);
assert_eq!(BigUint::new(~[0, 0, -1]).to_int_opt(), None);
}
#[test]
@ -1405,8 +1468,19 @@ fn check(v: ~[BigDigit], u: uint) {
check(~[ 0, -1], uint::max_value << BigDigit::bits);
check(~[-1, -1], uint::max_value);
assert_eq!(BigUint::new(~[0, 0, 1]).to_uint(), uint::max_value);
assert_eq!(BigUint::new(~[0, 0, -1]).to_uint(), uint::max_value);
assert_eq!(BigUint::new(~[0, 0, 1]).to_uint_opt(), None);
assert_eq!(BigUint::new(~[0, 0, -1]).to_uint_opt(), None);
}
#[test]
fn test_convert_to_bigint() {
fn check(n: BigUint, ans: BigInt) {
assert_eq!(n.to_bigint(), ans);
assert_eq!(n.to_bigint().to_biguint(), n);
}
check(Zero::zero(), Zero::zero());
check(BigUint::new(~[1,2,3]),
BigInt::from_biguint(Plus, BigUint::new(~[1,2,3])));
}
static sum_triples: &'static [(&'static [BigDigit],
@ -1793,22 +1867,21 @@ fn check(b: BigInt, i: int) {
Plus, BigUint::from_uint(int::max_value as uint)
), int::max_value);
assert!(BigInt::from_biguint(
assert_eq!(BigInt::from_biguint(
Plus, BigUint::from_uint(int::max_value as uint + 1)
).to_int() == int::max_value);
assert!(BigInt::from_biguint(
).to_int_opt(), None);
assert_eq!(BigInt::from_biguint(
Plus, BigUint::new(~[1, 2, 3])
).to_int() == int::max_value);
).to_int_opt(), None);
check(BigInt::from_biguint(
Minus, BigUint::from_uint(-int::min_value as uint)
Minus, BigUint::new(~[0, 1<<(BigDigit::bits-1)])
), int::min_value);
assert!(BigInt::from_biguint(
Minus, BigUint::from_uint(-int::min_value as uint + 1)
).to_int() == int::min_value);
assert!(BigInt::from_biguint(
Minus, BigUint::new(~[1, 2, 3])
).to_int() == int::min_value);
assert_eq!(BigInt::from_biguint(
Minus, BigUint::new(~[1, 1<<(BigDigit::bits-1)])
).to_int_opt(), None);
assert_eq!(BigInt::from_biguint(
Minus, BigUint::new(~[1, 2, 3])).to_int_opt(), None);
}
#[test]
@ -1824,16 +1897,31 @@ fn check(b: BigInt, u: uint) {
check(
BigInt::from_biguint(Plus, BigUint::from_uint(uint::max_value)),
uint::max_value);
assert!(BigInt::from_biguint(
Plus, BigUint::new(~[1, 2, 3])
).to_uint() == uint::max_value);
assert_eq!(BigInt::from_biguint(
Plus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
assert!(BigInt::from_biguint(
Minus, BigUint::from_uint(uint::max_value)
).to_uint() == 0);
assert!(BigInt::from_biguint(
Minus, BigUint::new(~[1, 2, 3])
).to_uint() == 0);
assert_eq!(BigInt::from_biguint(
Minus, BigUint::from_uint(uint::max_value)).to_uint_opt(), None);
assert_eq!(BigInt::from_biguint(
Minus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
}
#[test]
fn test_convert_to_biguint() {
fn check(n: BigInt, ans_1: BigUint) {
assert_eq!(n.to_biguint(), ans_1);
assert_eq!(n.to_biguint().to_bigint(), n);
}
let zero: BigInt = Zero::zero();
let unsigned_zero: BigUint = Zero::zero();
let positive = BigInt::from_biguint(
Plus, BigUint::new(~[1,2,3]));
let negative = -positive;
check(zero, unsigned_zero);
check(positive, BigUint::new(~[1,2,3]));
assert_eq!(negative.to_biguint_opt(), None);
}
static sum_triples: &'static [(&'static [BigDigit],