Skip to content

Commit 4c6bf48

Browse files
committed
auto merge of #9133 : dcrewi/rust/bigint-random-range, r=huonw
2 parents 4dc3a97 + af72e41 commit 4c6bf48

File tree

1 file changed

+140
-2
lines changed

1 file changed

+140
-2
lines changed

src/libextra/num/bigint.rs

+140-2
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,13 @@ impl BigUint {
697697
}
698698
return BigUint::new(shifted);
699699
}
700+
701+
/// Determines the fewest bits necessary to express the BigUint.
702+
pub fn bits(&self) -> uint {
703+
if self.is_zero() { return 0; }
704+
let zeros = self.data.last().leading_zeros();
705+
return self.data.len()*BigDigit::bits - (zeros as uint);
706+
}
700707
}
701708

702709
#[cfg(target_word_size = "64")]
@@ -1115,10 +1122,23 @@ trait RandBigInt {
11151122
11161123
/// Generate a random BigInt of the given bit size.
11171124
fn gen_bigint(&mut self, bit_size: uint) -> BigInt;
1125+
1126+
/// Generate a random BigUint less than the given bound. Fails
1127+
/// when the bound is zero.
1128+
fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint;
1129+
1130+
/// Generate a random BigUint within the given range. The lower
1131+
/// bound is inclusive; the upper bound is exclusive. Fails when
1132+
/// the upper bound is not greater than the lower bound.
1133+
fn gen_biguint_range(&mut self, lbound: &BigUint, ubound: &BigUint) -> BigUint;
1134+
1135+
/// Generate a random BigInt within the given range. The lower
1136+
/// bound is inclusive; the upper bound is exclusive. Fails when
1137+
/// the upper bound is not greater than the lower bound.
1138+
fn gen_bigint_range(&mut self, lbound: &BigInt, ubound: &BigInt) -> BigInt;
11181139
}
11191140
11201141
impl<R: Rng> RandBigInt for R {
1121-
/// Generate a random BigUint of the given bit size.
11221142
fn gen_biguint(&mut self, bit_size: uint) -> BigUint {
11231143
let (digits, rem) = bit_size.div_rem(&BigDigit::bits);
11241144
let mut data = vec::with_capacity(digits+1);
@@ -1132,7 +1152,6 @@ impl<R: Rng> RandBigInt for R {
11321152
return BigUint::new(data);
11331153
}
11341154
1135-
/// Generate a random BigInt of the given bit size.
11361155
fn gen_bigint(&mut self, bit_size: uint) -> BigInt {
11371156
// Generate a random BigUint...
11381157
let biguint = self.gen_biguint(bit_size);
@@ -1154,6 +1173,32 @@ impl<R: Rng> RandBigInt for R {
11541173
};
11551174
return BigInt::from_biguint(sign, biguint);
11561175
}
1176+
1177+
fn gen_biguint_below(&mut self, bound: &BigUint) -> BigUint {
1178+
assert!(!bound.is_zero());
1179+
let bits = bound.bits();
1180+
loop {
1181+
let n = self.gen_biguint(bits);
1182+
if n < *bound { return n; }
1183+
}
1184+
}
1185+
1186+
fn gen_biguint_range(&mut self,
1187+
lbound: &BigUint,
1188+
ubound: &BigUint)
1189+
-> BigUint {
1190+
assert!(*lbound < *ubound);
1191+
return *lbound + self.gen_biguint_below(&(*ubound - *lbound));
1192+
}
1193+
1194+
fn gen_bigint_range(&mut self,
1195+
lbound: &BigInt,
1196+
ubound: &BigInt)
1197+
-> BigInt {
1198+
assert!(*lbound < *ubound);
1199+
let delta = (*ubound - *lbound).to_biguint();
1200+
return *lbound + self.gen_biguint_below(&delta).to_bigint();
1201+
}
11571202
}
11581203
11591204
impl BigInt {
@@ -1780,12 +1825,63 @@ mod biguint_tests {
17801825
check(30, "265252859812191058636308480000000");
17811826
}
17821827

1828+
#[test]
1829+
fn test_bits() {
1830+
assert_eq!(BigUint::new(~[0,0,0,0]).bits(), 0);
1831+
assert_eq!(BigUint::from_uint(0).bits(), 0);
1832+
assert_eq!(BigUint::from_uint(1).bits(), 1);
1833+
assert_eq!(BigUint::from_uint(3).bits(), 2);
1834+
let n: BigUint = FromStrRadix::from_str_radix("4000000000", 16).unwrap();
1835+
assert_eq!(n.bits(), 39);
1836+
let one: BigUint = One::one();
1837+
assert_eq!((one << 426).bits(), 427);
1838+
}
1839+
17831840
#[test]
17841841
fn test_rand() {
17851842
let mut rng = task_rng();
17861843
let _n: BigUint = rng.gen_biguint(137);
17871844
assert!(rng.gen_biguint(0).is_zero());
17881845
}
1846+
1847+
#[test]
1848+
fn test_rand_range() {
1849+
let mut rng = task_rng();
1850+
1851+
do 10.times {
1852+
assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236),
1853+
&BigInt::from_uint(237)),
1854+
BigInt::from_uint(236));
1855+
}
1856+
1857+
let l = BigUint::from_uint(403469000 + 2352);
1858+
let u = BigUint::from_uint(403469000 + 3513);
1859+
do 1000.times {
1860+
let n: BigUint = rng.gen_biguint_below(&u);
1861+
assert!(n < u);
1862+
1863+
let n: BigUint = rng.gen_biguint_range(&l, &u);
1864+
assert!(n >= l);
1865+
assert!(n < u);
1866+
}
1867+
}
1868+
1869+
#[test]
1870+
#[should_fail]
1871+
fn test_zero_rand_range() {
1872+
task_rng().gen_biguint_range(&BigUint::from_uint(54),
1873+
&BigUint::from_uint(54));
1874+
}
1875+
1876+
#[test]
1877+
#[should_fail]
1878+
fn test_negative_rand_range() {
1879+
let mut rng = task_rng();
1880+
let l = BigUint::from_uint(2352);
1881+
let u = BigUint::from_uint(3513);
1882+
// Switching u and l should fail:
1883+
let _n: BigUint = rng.gen_biguint_range(&u, &l);
1884+
}
17891885
}
17901886

17911887
#[cfg(test)]
@@ -2237,6 +2333,48 @@ mod bigint_tests {
22372333
let _n: BigInt = rng.gen_bigint(137);
22382334
assert!(rng.gen_bigint(0).is_zero());
22392335
}
2336+
2337+
#[test]
2338+
fn test_rand_range() {
2339+
let mut rng = task_rng();
2340+
2341+
do 10.times {
2342+
assert_eq!(rng.gen_bigint_range(&BigInt::from_uint(236),
2343+
&BigInt::from_uint(237)),
2344+
BigInt::from_uint(236));
2345+
}
2346+
2347+
fn check(l: BigInt, u: BigInt) {
2348+
let mut rng = task_rng();
2349+
do 1000.times {
2350+
let n: BigInt = rng.gen_bigint_range(&l, &u);
2351+
assert!(n >= l);
2352+
assert!(n < u);
2353+
}
2354+
}
2355+
let l = BigInt::from_uint(403469000 + 2352);
2356+
let u = BigInt::from_uint(403469000 + 3513);
2357+
check( l.clone(), u.clone());
2358+
check(-l.clone(), u.clone());
2359+
check(-u.clone(), -l.clone());
2360+
}
2361+
2362+
#[test]
2363+
#[should_fail]
2364+
fn test_zero_rand_range() {
2365+
task_rng().gen_bigint_range(&IntConvertible::from_int(54),
2366+
&IntConvertible::from_int(54));
2367+
}
2368+
2369+
#[test]
2370+
#[should_fail]
2371+
fn test_negative_rand_range() {
2372+
let mut rng = task_rng();
2373+
let l = BigInt::from_uint(2352);
2374+
let u = BigInt::from_uint(3513);
2375+
// Switching u and l should fail:
2376+
let _n: BigInt = rng.gen_bigint_range(&u, &l);
2377+
}
22402378
}
22412379

22422380
#[cfg(test)]

0 commit comments

Comments
 (0)