Skip to content

Commit 91ab8a3

Browse files
committed
auto merge of #9014 : dcrewi/rust/convert-between-bigints, r=anasazi
2 parents 7f0d261 + 9bee3d7 commit 91ab8a3

File tree

1 file changed

+130
-42
lines changed

1 file changed

+130
-42
lines changed

src/libextra/num/bigint.rs

+130-42
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ impl Integer for BigUint {
503503
impl IntConvertible for BigUint {
504504
#[inline]
505505
fn to_int(&self) -> int {
506-
num::min(self.to_uint(), int::max_value as uint) as int
506+
self.to_int_opt().expect("BigUint conversion would overflow int")
507507
}
508508

509509
#[inline]
@@ -615,18 +615,43 @@ impl BigUint {
615615
}
616616

617617

618-
/// Converts this big integer into a uint, returning the uint::max_value if
619-
/// it's too large to fit in a uint.
618+
/// Converts this BigUint into a uint, failing if the conversion
619+
/// would overflow.
620620
#[inline]
621621
pub fn to_uint(&self) -> uint {
622+
self.to_uint_opt().expect("BigUint conversion would overflow uint")
623+
}
624+
625+
/// Converts this BigUint into a uint, unless it would overflow.
626+
#[inline]
627+
pub fn to_uint_opt(&self) -> Option<uint> {
622628
match self.data.len() {
623-
0 => 0,
624-
1 => self.data[0] as uint,
625-
2 => BigDigit::to_uint(self.data[1], self.data[0]),
626-
_ => uint::max_value
629+
0 => Some(0),
630+
1 => Some(self.data[0] as uint),
631+
2 => Some(BigDigit::to_uint(self.data[1], self.data[0])),
632+
_ => None
627633
}
628634
}
629635

636+
// Converts this BigUint into an int, unless it would overflow.
637+
pub fn to_int_opt(&self) -> Option<int> {
638+
self.to_uint_opt().chain(|n| {
639+
// If top bit of uint is set, it's too large to convert to
640+
// int.
641+
if (n >> (2*BigDigit::bits - 1) != 0) {
642+
None
643+
} else {
644+
Some(n as int)
645+
}
646+
})
647+
}
648+
649+
/// Converts this BigUint into a BigInt.
650+
#[inline]
651+
pub fn to_bigint(&self) -> BigInt {
652+
BigInt::from_biguint(Plus, self.clone())
653+
}
654+
630655
#[inline]
631656
fn shl_unit(&self, n_unit: uint) -> BigUint {
632657
if n_unit == 0 || self.is_zero() { return (*self).clone(); }
@@ -1048,12 +1073,7 @@ impl Integer for BigInt {
10481073
impl IntConvertible for BigInt {
10491074
#[inline]
10501075
fn to_int(&self) -> int {
1051-
match self.sign {
1052-
Plus => num::min(self.to_uint(), int::max_value as uint) as int,
1053-
Zero => 0,
1054-
Minus => num::min((-self).to_uint(),
1055-
(int::max_value as uint) + 1) as int
1056-
}
1076+
self.to_int_opt().expect("BigInt conversion would overflow int")
10571077
}
10581078

10591079
#[inline]
@@ -1179,12 +1199,55 @@ impl BigInt {
11791199
.map_move(|bu| BigInt::from_biguint(sign, bu));
11801200
}
11811201
1202+
/// Converts this BigInt into a uint, failing if the conversion
1203+
/// would overflow.
11821204
#[inline]
11831205
pub fn to_uint(&self) -> uint {
1206+
self.to_uint_opt().expect("BigInt conversion would overflow uint")
1207+
}
1208+
1209+
/// Converts this BigInt into a uint, unless it would overflow.
1210+
#[inline]
1211+
pub fn to_uint_opt(&self) -> Option<uint> {
1212+
match self.sign {
1213+
Plus => self.data.to_uint_opt(),
1214+
Zero => Some(0),
1215+
Minus => None
1216+
}
1217+
}
1218+
1219+
/// Converts this BigInt into an int, unless it would overflow.
1220+
pub fn to_int_opt(&self) -> Option<int> {
1221+
match self.sign {
1222+
Plus => self.data.to_int_opt(),
1223+
Zero => Some(0),
1224+
Minus => self.data.to_uint_opt().chain(|n| {
1225+
let m: uint = 1 << (2*BigDigit::bits-1);
1226+
if (n > m) {
1227+
None
1228+
} else if (n == m) {
1229+
Some(int::min_value)
1230+
} else {
1231+
Some(-(n as int))
1232+
}
1233+
})
1234+
}
1235+
}
1236+
1237+
/// Converts this BigInt into a BigUint, failing if BigInt is
1238+
/// negative.
1239+
#[inline]
1240+
pub fn to_biguint(&self) -> BigUint {
1241+
self.to_biguint_opt().expect("negative BigInt cannot convert to BigUint")
1242+
}
1243+
1244+
/// Converts this BigInt into a BigUint, if it's not negative.
1245+
#[inline]
1246+
pub fn to_biguint_opt(&self) -> Option<BigUint> {
11841247
match self.sign {
1185-
Plus => self.data.to_uint(),
1186-
Zero => 0,
1187-
Minus => 0
1248+
Plus => Some(self.data.clone()),
1249+
Zero => Some(Zero::zero()),
1250+
Minus => None
11881251
}
11891252
}
11901253
}
@@ -1385,9 +1448,9 @@ mod biguint_tests {
13851448
check(~[ 0, 1], ((uint::max_value >> BigDigit::bits) + 1) as int);
13861449
check(~[-1, -1 >> 1], int::max_value);
13871450

1388-
assert_eq!(BigUint::new(~[0, -1]).to_int(), int::max_value);
1389-
assert_eq!(BigUint::new(~[0, 0, 1]).to_int(), int::max_value);
1390-
assert_eq!(BigUint::new(~[0, 0, -1]).to_int(), int::max_value);
1451+
assert_eq!(BigUint::new(~[0, -1]).to_int_opt(), None);
1452+
assert_eq!(BigUint::new(~[0, 0, 1]).to_int_opt(), None);
1453+
assert_eq!(BigUint::new(~[0, 0, -1]).to_int_opt(), None);
13911454
}
13921455

13931456
#[test]
@@ -1405,8 +1468,19 @@ mod biguint_tests {
14051468
check(~[ 0, -1], uint::max_value << BigDigit::bits);
14061469
check(~[-1, -1], uint::max_value);
14071470

1408-
assert_eq!(BigUint::new(~[0, 0, 1]).to_uint(), uint::max_value);
1409-
assert_eq!(BigUint::new(~[0, 0, -1]).to_uint(), uint::max_value);
1471+
assert_eq!(BigUint::new(~[0, 0, 1]).to_uint_opt(), None);
1472+
assert_eq!(BigUint::new(~[0, 0, -1]).to_uint_opt(), None);
1473+
}
1474+
1475+
#[test]
1476+
fn test_convert_to_bigint() {
1477+
fn check(n: BigUint, ans: BigInt) {
1478+
assert_eq!(n.to_bigint(), ans);
1479+
assert_eq!(n.to_bigint().to_biguint(), n);
1480+
}
1481+
check(Zero::zero(), Zero::zero());
1482+
check(BigUint::new(~[1,2,3]),
1483+
BigInt::from_biguint(Plus, BigUint::new(~[1,2,3])));
14101484
}
14111485

14121486
static sum_triples: &'static [(&'static [BigDigit],
@@ -1793,22 +1867,21 @@ mod bigint_tests {
17931867
Plus, BigUint::from_uint(int::max_value as uint)
17941868
), int::max_value);
17951869

1796-
assert!(BigInt::from_biguint(
1870+
assert_eq!(BigInt::from_biguint(
17971871
Plus, BigUint::from_uint(int::max_value as uint + 1)
1798-
).to_int() == int::max_value);
1799-
assert!(BigInt::from_biguint(
1872+
).to_int_opt(), None);
1873+
assert_eq!(BigInt::from_biguint(
18001874
Plus, BigUint::new(~[1, 2, 3])
1801-
).to_int() == int::max_value);
1875+
).to_int_opt(), None);
18021876

18031877
check(BigInt::from_biguint(
1804-
Minus, BigUint::from_uint(-int::min_value as uint)
1878+
Minus, BigUint::new(~[0, 1<<(BigDigit::bits-1)])
18051879
), int::min_value);
1806-
assert!(BigInt::from_biguint(
1807-
Minus, BigUint::from_uint(-int::min_value as uint + 1)
1808-
).to_int() == int::min_value);
1809-
assert!(BigInt::from_biguint(
1810-
Minus, BigUint::new(~[1, 2, 3])
1811-
).to_int() == int::min_value);
1880+
assert_eq!(BigInt::from_biguint(
1881+
Minus, BigUint::new(~[1, 1<<(BigDigit::bits-1)])
1882+
).to_int_opt(), None);
1883+
assert_eq!(BigInt::from_biguint(
1884+
Minus, BigUint::new(~[1, 2, 3])).to_int_opt(), None);
18121885
}
18131886

18141887
#[test]
@@ -1824,16 +1897,31 @@ mod bigint_tests {
18241897
check(
18251898
BigInt::from_biguint(Plus, BigUint::from_uint(uint::max_value)),
18261899
uint::max_value);
1827-
assert!(BigInt::from_biguint(
1828-
Plus, BigUint::new(~[1, 2, 3])
1829-
).to_uint() == uint::max_value);
1830-
1831-
assert!(BigInt::from_biguint(
1832-
Minus, BigUint::from_uint(uint::max_value)
1833-
).to_uint() == 0);
1834-
assert!(BigInt::from_biguint(
1835-
Minus, BigUint::new(~[1, 2, 3])
1836-
).to_uint() == 0);
1900+
assert_eq!(BigInt::from_biguint(
1901+
Plus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
1902+
1903+
assert_eq!(BigInt::from_biguint(
1904+
Minus, BigUint::from_uint(uint::max_value)).to_uint_opt(), None);
1905+
assert_eq!(BigInt::from_biguint(
1906+
Minus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
1907+
}
1908+
1909+
#[test]
1910+
fn test_convert_to_biguint() {
1911+
fn check(n: BigInt, ans_1: BigUint) {
1912+
assert_eq!(n.to_biguint(), ans_1);
1913+
assert_eq!(n.to_biguint().to_bigint(), n);
1914+
}
1915+
let zero: BigInt = Zero::zero();
1916+
let unsigned_zero: BigUint = Zero::zero();
1917+
let positive = BigInt::from_biguint(
1918+
Plus, BigUint::new(~[1,2,3]));
1919+
let negative = -positive;
1920+
1921+
check(zero, unsigned_zero);
1922+
check(positive, BigUint::new(~[1,2,3]));
1923+
1924+
assert_eq!(negative.to_biguint_opt(), None);
18371925
}
18381926

18391927
static sum_triples: &'static [(&'static [BigDigit],

0 commit comments

Comments
 (0)