Skip to content

Commit 0e8ad4d

Browse files
committed
extra: fix BigInt on 32bit machines
1 parent efae73d commit 0e8ad4d

File tree

1 file changed

+139
-127
lines changed

1 file changed

+139
-127
lines changed

src/libextra/num/bigint.rs

+139-127
Original file line numberDiff line numberDiff line change
@@ -506,10 +506,10 @@ impl ToPrimitive for BigUint {
506506
fn to_i64(&self) -> Option<i64> {
507507
do self.to_u64().and_then |n| {
508508
// If top bit of u64 is set, it's too large to convert to i64.
509-
if (n >> (2*BigDigit::bits - 1) != 0) {
510-
None
511-
} else {
509+
if n >> 63 == 0 {
512510
Some(n as i64)
511+
} else {
512+
None
513513
}
514514
}
515515
}
@@ -562,10 +562,12 @@ impl ToPrimitive for BigUint {
562562
impl FromPrimitive for BigUint {
563563
#[inline]
564564
fn from_i64(n: i64) -> Option<BigUint> {
565-
if (n < 0) {
565+
if (n > 0) {
566+
FromPrimitive::from_u64(n as u64)
567+
} else if (n == 0) {
566568
Some(Zero::zero())
567569
} else {
568-
FromPrimitive::from_u64(n as u64)
570+
None
569571
}
570572
}
571573

@@ -802,30 +804,6 @@ impl BigUint {
802804
}
803805
}
804806

805-
#[cfg(target_word_size = "64")]
806-
#[inline]
807-
fn get_radix_base(radix: uint) -> (uint, uint) {
808-
assert!(1 < radix && radix <= 16);
809-
match radix {
810-
2 => (4294967296, 32),
811-
3 => (3486784401, 20),
812-
4 => (4294967296, 16),
813-
5 => (1220703125, 13),
814-
6 => (2176782336, 12),
815-
7 => (1977326743, 11),
816-
8 => (1073741824, 10),
817-
9 => (3486784401, 10),
818-
10 => (1000000000, 9),
819-
11 => (2357947691, 9),
820-
12 => (429981696, 8),
821-
13 => (815730721, 8),
822-
14 => (1475789056, 8),
823-
15 => (2562890625, 8),
824-
16 => (4294967296, 8),
825-
_ => fail2!()
826-
}
827-
}
828-
829807
#[cfg(target_word_size = "32")]
830808
#[inline]
831809
fn get_radix_base(radix: uint) -> (uint, uint) {
@@ -850,6 +828,30 @@ fn get_radix_base(radix: uint) -> (uint, uint) {
850828
}
851829
}
852830

831+
#[cfg(target_word_size = "64")]
832+
#[inline]
833+
fn get_radix_base(radix: uint) -> (uint, uint) {
834+
assert!(1 < radix && radix <= 16);
835+
match radix {
836+
2 => (4294967296, 32),
837+
3 => (3486784401, 20),
838+
4 => (4294967296, 16),
839+
5 => (1220703125, 13),
840+
6 => (2176782336, 12),
841+
7 => (1977326743, 11),
842+
8 => (1073741824, 10),
843+
9 => (3486784401, 10),
844+
10 => (1000000000, 9),
845+
11 => (2357947691, 9),
846+
12 => (429981696, 8),
847+
13 => (815730721, 8),
848+
14 => (1475789056, 8),
849+
15 => (2562890625, 8),
850+
16 => (4294967296, 8),
851+
_ => fail2!()
852+
}
853+
}
854+
853855
/// A Sign is a `BigInt`'s composing element.
854856
#[deriving(Eq, Clone)]
855857
pub enum Sign { Minus, Zero, Plus }
@@ -1181,13 +1183,13 @@ impl ToPrimitive for BigInt {
11811183
Zero => Some(0),
11821184
Minus => {
11831185
do self.data.to_u64().and_then |n| {
1184-
let m: u64 = 1 << (2*BigDigit::bits-1);
1185-
if (n > m) {
1186-
None
1187-
} else if (n == m) {
1186+
let m: u64 = 1 << 63;
1187+
if n < m {
1188+
Some(-(n as i64))
1189+
} else if n == m {
11881190
Some(i64::min_value)
11891191
} else {
1190-
Some(-(n as i64))
1192+
None
11911193
}
11921194
}
11931195
}
@@ -1431,16 +1433,15 @@ impl BigInt {
14311433
14321434
#[cfg(test)]
14331435
mod biguint_tests {
1434-
14351436
use super::*;
14361437
14371438
use std::cmp::{Less, Equal, Greater};
1438-
use std::int;
1439+
use std::i64;
14391440
use std::num::{Zero, One, FromStrRadix};
14401441
use std::num::{ToPrimitive, FromPrimitive};
14411442
use std::rand::{task_rng};
14421443
use std::str;
1443-
use std::uint;
1444+
use std::u64;
14441445
use std::vec;
14451446
14461447
#[test]
@@ -1612,44 +1613,110 @@ mod biguint_tests {
16121613
"88887777666655554444333322221111");
16131614
}
16141615

1616+
#[cfg(target_word_size = "32")]
1617+
#[test]
1618+
fn test_convert_i64() {
1619+
fn check(b1: BigUint, i: i64) {
1620+
let b2: BigUint = FromPrimitive::from_i64(i).unwrap();
1621+
assert!(b1 == b2);
1622+
assert!(b1.to_i64().unwrap() == i);
1623+
}
1624+
1625+
check(Zero::zero(), 0);
1626+
check(One::one(), 1);
1627+
check(i64::max_value.to_biguint().unwrap(), i64::max_value);
1628+
1629+
check(BigUint::new(~[ ]), 0);
1630+
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
1631+
check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1);
1632+
check(BigUint::new(~[ 0, 1 ]), (1 << (1*BigDigit::bits)));
1633+
check(BigUint::new(~[-1, -1 ]), (1 << (2*BigDigit::bits)) - 1);
1634+
check(BigUint::new(~[ 0, 0, 1 ]), (1 << (2*BigDigit::bits)));
1635+
check(BigUint::new(~[-1, -1, -1 ]), (1 << (3*BigDigit::bits)) - 1);
1636+
check(BigUint::new(~[ 0, 0, 0, 1 ]), (1 << (3*BigDigit::bits)));
1637+
check(BigUint::new(~[-1, -1, -1, -1 >> 1]), i64::max_value);
1638+
1639+
assert_eq!(i64::min_value.to_biguint(), None);
1640+
assert_eq!(BigUint::new(~[-1, -1, -1, -1 ]).to_i64(), None);
1641+
assert_eq!(BigUint::new(~[ 0, 0, 0, 0, 1]).to_i64(), None);
1642+
assert_eq!(BigUint::new(~[-1, -1, -1, -1, -1]).to_i64(), None);
1643+
}
1644+
1645+
#[cfg(target_word_size = "64")]
16151646
#[test]
1616-
fn test_convert_int() {
1617-
fn check(v: ~[BigDigit], i: int) {
1618-
let b1 = BigUint::new(v);
1619-
let b2: BigUint = FromPrimitive::from_int(i).unwrap();
1647+
fn test_convert_i64() {
1648+
fn check(b1: BigUint, i: i64) {
1649+
let b2: BigUint = FromPrimitive::from_i64(i).unwrap();
1650+
assert!(b1 == b2);
1651+
assert!(b1.to_i64().unwrap() == i);
1652+
}
1653+
1654+
check(Zero::zero(), 0);
1655+
check(One::one(), 1);
1656+
check(i64::max_value.to_biguint().unwrap(), i64::max_value);
1657+
1658+
check(BigUint::new(~[ ]), 0);
1659+
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
1660+
check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1);
1661+
check(BigUint::new(~[ 0, 1 ]), (1 << (1*BigDigit::bits)));
1662+
check(BigUint::new(~[-1, -1 >> 1]), i64::max_value);
1663+
1664+
assert_eq!(i64::min_value.to_biguint(), None);
1665+
assert_eq!(BigUint::new(~[-1, -1 ]).to_i64(), None);
1666+
assert_eq!(BigUint::new(~[ 0, 0, 1]).to_i64(), None);
1667+
assert_eq!(BigUint::new(~[-1, -1, -1]).to_i64(), None);
1668+
}
1669+
1670+
#[cfg(target_word_size = "32")]
1671+
#[test]
1672+
fn test_convert_u64() {
1673+
fn check(b1: BigUint, u: u64) {
1674+
let b2: BigUint = FromPrimitive::from_u64(u).unwrap();
16201675
assert!(b1 == b2);
1621-
assert!(b1.to_int().unwrap() == i);
1676+
assert!(b1.to_u64().unwrap() == u);
16221677
}
16231678

1624-
check(~[], 0);
1625-
check(~[1], 1);
1626-
check(~[-1], (uint::max_value >> BigDigit::bits) as int);
1627-
check(~[ 0, 1], ((uint::max_value >> BigDigit::bits) + 1) as int);
1628-
check(~[-1, -1 >> 1], int::max_value);
1679+
check(Zero::zero(), 0);
1680+
check(One::one(), 1);
1681+
check(u64::min_value.to_biguint().unwrap(), u64::min_value);
1682+
check(u64::max_value.to_biguint().unwrap(), u64::max_value);
1683+
1684+
check(BigUint::new(~[ ]), 0);
1685+
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
1686+
check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1);
1687+
check(BigUint::new(~[ 0, 1 ]), (1 << (1*BigDigit::bits)));
1688+
check(BigUint::new(~[-1, -1 ]), (1 << (2*BigDigit::bits)) - 1);
1689+
check(BigUint::new(~[ 0, 0, 1 ]), (1 << (2*BigDigit::bits)));
1690+
check(BigUint::new(~[-1, -1, -1 ]), (1 << (3*BigDigit::bits)) - 1);
1691+
check(BigUint::new(~[ 0, 0, 0, 1]), (1 << (3*BigDigit::bits)));
1692+
check(BigUint::new(~[-1, -1, -1, -1]), u64::max_value);
16291693

1630-
assert_eq!(BigUint::new(~[0, -1]).to_int(), None);
1631-
assert_eq!(BigUint::new(~[0, 0, 1]).to_int(), None);
1632-
assert_eq!(BigUint::new(~[0, 0, -1]).to_int(), None);
1694+
assert_eq!(BigUint::new(~[ 0, 0, 0, 0, 1]).to_u64(), None);
1695+
assert_eq!(BigUint::new(~[-1, -1, -1, -1, -1]).to_u64(), None);
16331696
}
16341697

1698+
#[cfg(target_word_size = "64")]
16351699
#[test]
1636-
fn test_convert_uint() {
1637-
fn check(v: ~[BigDigit], u: uint) {
1638-
let b1 = BigUint::new(v);
1639-
let b2: BigUint = FromPrimitive::from_uint(u).unwrap();
1700+
fn test_convert_u64() {
1701+
fn check(b1: BigUint, u: u64) {
1702+
let b2: BigUint = FromPrimitive::from_u64(u).unwrap();
16401703
assert!(b1 == b2);
1641-
assert!(b1.to_uint().unwrap() == u);
1704+
assert!(b1.to_u64().unwrap() == u);
16421705
}
16431706

1644-
check(~[], 0);
1645-
check(~[ 1], 1);
1646-
check(~[-1], uint::max_value >> BigDigit::bits);
1647-
check(~[ 0, 1], (uint::max_value >> BigDigit::bits) + 1);
1648-
check(~[ 0, -1], uint::max_value << BigDigit::bits);
1649-
check(~[-1, -1], uint::max_value);
1707+
check(Zero::zero(), 0);
1708+
check(One::one(), 1);
1709+
check(u64::min_value.to_biguint().unwrap(), u64::min_value);
1710+
check(u64::max_value.to_biguint().unwrap(), u64::max_value);
1711+
1712+
check(BigUint::new(~[ ]), 0);
1713+
check(BigUint::new(~[ 1 ]), (1 << (0*BigDigit::bits)));
1714+
check(BigUint::new(~[-1 ]), (1 << (1*BigDigit::bits)) - 1);
1715+
check(BigUint::new(~[ 0, 1]), (1 << (1*BigDigit::bits)));
1716+
check(BigUint::new(~[-1, -1]), u64::max_value);
16501717

1651-
assert_eq!(BigUint::new(~[0, 0, 1]).to_uint(), None);
1652-
assert_eq!(BigUint::new(~[0, 0, -1]).to_uint(), None);
1718+
assert_eq!(BigUint::new(~[ 0, 0, 1]).to_u64(), None);
1719+
assert_eq!(BigUint::new(~[-1, -1, -1]).to_u64(), None);
16531720
}
16541721

16551722
#[test]
@@ -2025,10 +2092,11 @@ mod bigint_tests {
20252092
use super::*;
20262093

20272094
use std::cmp::{Less, Equal, Greater};
2028-
use std::{int, i64, uint, u64};
2095+
use std::i64;
20292096
use std::num::{Zero, One, FromStrRadix};
20302097
use std::num::{ToPrimitive, FromPrimitive};
20312098
use std::rand::{task_rng};
2099+
use std::u64;
20322100

20332101
#[test]
20342102
fn test_from_biguint() {
@@ -2086,59 +2154,6 @@ mod bigint_tests {
20862154
}
20872155
}
20882156

2089-
#[test]
2090-
fn test_convert_int() {
2091-
fn check(b1: BigInt, i: int) {
2092-
let b2: BigInt = FromPrimitive::from_int(i).unwrap();
2093-
assert!(b1 == b2);
2094-
assert!(b1.to_int().unwrap() == i);
2095-
}
2096-
2097-
check(Zero::zero(), 0);
2098-
check(One::one(), 1);
2099-
check(BigInt::from_biguint(
2100-
Plus, FromPrimitive::from_uint(int::max_value as uint).unwrap()
2101-
), int::max_value);
2102-
2103-
assert_eq!(BigInt::from_biguint(
2104-
Plus, FromPrimitive::from_uint(int::max_value as uint + 1).unwrap()
2105-
).to_int(), None);
2106-
assert_eq!(BigInt::from_biguint(
2107-
Plus, BigUint::new(~[1, 2, 3])
2108-
).to_int(), None);
2109-
2110-
check(BigInt::from_biguint(
2111-
Minus, BigUint::new(~[0, 1<<(BigDigit::bits-1)])
2112-
), int::min_value);
2113-
assert_eq!(BigInt::from_biguint(
2114-
Minus, BigUint::new(~[1, 1<<(BigDigit::bits-1)])
2115-
).to_int(), None);
2116-
assert_eq!(BigInt::from_biguint(
2117-
Minus, BigUint::new(~[1, 2, 3])).to_int(), None);
2118-
}
2119-
2120-
#[test]
2121-
fn test_convert_uint() {
2122-
fn check(b1: BigInt, u: uint) {
2123-
let b2: BigInt = FromPrimitive::from_uint(u).unwrap();
2124-
assert!(b1 == b2);
2125-
assert!(b1.to_uint().unwrap() == u);
2126-
}
2127-
2128-
check(Zero::zero(), 0);
2129-
check(One::one(), 1);
2130-
2131-
check(
2132-
BigInt::from_biguint(Plus, FromPrimitive::from_uint(uint::max_value).unwrap()),
2133-
uint::max_value);
2134-
assert_eq!(BigInt::from_biguint(
2135-
Plus, BigUint::new(~[1, 2, 3])).to_uint(), None);
2136-
2137-
let max_value: BigUint = FromPrimitive::from_uint(uint::max_value).unwrap();
2138-
assert_eq!(BigInt::from_biguint(Minus, max_value).to_uint(), None);
2139-
assert_eq!(BigInt::from_biguint(Minus, BigUint::new(~[1, 2, 3])).to_uint(), None);
2140-
}
2141-
21422157
#[test]
21432158
fn test_convert_i64() {
21442159
fn check(b1: BigInt, i: i64) {
@@ -2153,19 +2168,15 @@ mod bigint_tests {
21532168
check(i64::max_value.to_bigint().unwrap(), i64::max_value);
21542169

21552170
assert_eq!(
2156-
(i64::max_value as uint + 1).to_bigint().unwrap().to_i64(),
2171+
(i64::max_value as u64 + 1).to_bigint().unwrap().to_i64(),
21572172
None);
21582173

21592174
assert_eq!(
2160-
BigInt::from_biguint(Plus, BigUint::new(~[1, 2, 3, 4, 5])).to_i64(),
2175+
BigInt::from_biguint(Plus, BigUint::new(~[1, 2, 3, 4, 5])).to_i64(),
21612176
None);
21622177

2163-
check(
2164-
BigInt::from_biguint(Minus, BigUint::new(~[0, 1<<(BigDigit::bits-1)])),
2165-
i64::min_value);
2166-
21672178
assert_eq!(
2168-
BigInt::from_biguint(Minus, BigUint::new(~[1, 1<<(BigDigit::bits-1)])).to_i64(),
2179+
BigInt::from_biguint(Minus, BigUint::new(~[1, 0, 0, 1<<(BigDigit::bits-1)])).to_i64(),
21692180
None);
21702181

21712182
assert_eq!(
@@ -2183,15 +2194,16 @@ mod bigint_tests {
21832194

21842195
check(Zero::zero(), 0);
21852196
check(One::one(), 1);
2197+
check(u64::min_value.to_bigint().unwrap(), u64::min_value);
21862198
check(u64::max_value.to_bigint().unwrap(), u64::max_value);
21872199

21882200
assert_eq!(
2189-
BigInt::from_biguint(Plus, BigUint::new(~[1, 2, 3, 4, 5])).to_uint(),
2201+
BigInt::from_biguint(Plus, BigUint::new(~[1, 2, 3, 4, 5])).to_u64(),
21902202
None);
21912203

2192-
let max_value: BigUint = FromPrimitive::from_uint(uint::max_value).unwrap();
2204+
let max_value: BigUint = FromPrimitive::from_u64(u64::max_value).unwrap();
21932205
assert_eq!(BigInt::from_biguint(Minus, max_value).to_u64(), None);
2194-
assert_eq!(BigInt::from_biguint(Minus, BigUint::new(~[1, 2, 3])).to_u64(), None);
2206+
assert_eq!(BigInt::from_biguint(Minus, BigUint::new(~[1, 2, 3, 4, 5])).to_u64(), None);
21952207
}
21962208

21972209
#[test]

0 commit comments

Comments
 (0)