Skip to content

Commit 245fde0

Browse files
authored
Merge pull request #792 from dhardy/features
Use ChaCha20 in StdRng and feature-gate SmallRng
2 parents e108c47 + ff121cf commit 245fde0

30 files changed

+268
-241
lines changed

Cargo.toml

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,30 @@ keywords = ["random", "rng"]
1414
categories = ["algorithms", "no-std"]
1515
build = "build.rs"
1616
exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
17+
autobenches = true
1718

1819
[badges]
1920
travis-ci = { repository = "rust-random/rand" }
2021
appveyor = { repository = "rust-random/rand" }
2122

2223
[features]
24+
# Meta-features:
2325
default = ["std"] # without "std" rand uses libcore
2426
nightly = ["simd_support"] # enables all features requiring nightly rust
27+
28+
# Optional dependencies:
2529
std = ["rand_core/std", "alloc", "getrandom"]
2630
alloc = ["rand_core/alloc"] # enables Vec and Box support (without std)
27-
i128_support = [] # enables i128 and u128 support
28-
simd_support = ["packed_simd"] # enables SIMD support
2931
serde1 = ["rand_core/serde1", "rand_isaac/serde1", "rand_xorshift/serde1"] # enables serialization for PRNGs
3032
# re-export optional WASM dependencies to avoid breakage:
3133
wasm-bindgen = ["getrandom_package/wasm-bindgen"]
3234
stdweb = ["getrandom_package/stdweb"]
3335
getrandom = ["getrandom_package", "rand_core/getrandom"]
3436

37+
# Configuration:
38+
simd_support = ["packed_simd"] # enables SIMD support
39+
small_rng = ["rand_pcg"] # enables SmallRng
40+
3541
[workspace]
3642
members = [
3743
"rand_core",
@@ -49,8 +55,7 @@ members = [
4955

5056
[dependencies]
5157
rand_core = { path = "rand_core", version = "0.4" }
52-
rand_pcg = { path = "rand_pcg", version = "0.1" }
53-
rand_hc = { path = "rand_hc", version = "0.1" }
58+
rand_pcg = { path = "rand_pcg", version = "0.1", optional = true }
5459
# Do not depend on 'getrandom_package' directly; use the 'getrandom' feature!
5560
getrandom_package = { version = "0.1.1", package = "getrandom", optional = true }
5661
log = { version = "0.4", optional = true }
@@ -66,17 +71,45 @@ features = ["into_bits"]
6671
# Used for fork protection (reseeding.rs)
6772
libc = { version = "0.2.22", default-features = false }
6873

74+
# Emscripten does not support 128-bit integers, which are used by ChaCha code.
75+
# We work around this by using a different RNG.
76+
[target.'cfg(not(target_os = "emscripten"))'.dependencies]
77+
rand_chacha = { path = "rand_chacha", version = "0.2" }
78+
[target.'cfg(target_os = "emscripten")'.dependencies]
79+
rand_hc = { path = "rand_hc", version = "0.1" }
80+
6981
[dev-dependencies]
82+
rand_pcg = { path = "rand_pcg", version = "0.1" }
7083
# Only for benches:
84+
rand_hc = { path = "rand_hc", version = "0.1" }
7185
rand_xoshiro = { path = "rand_xoshiro", version = "0.2" }
7286
rand_isaac = { path = "rand_isaac", version = "0.1" }
73-
rand_chacha = { path = "rand_chacha", version = "0.2" }
7487
rand_xorshift = { path = "rand_xorshift", version = "0.1" }
7588
rand_distr = { path = "rand_distr", version = "0.1" }
7689

7790
[build-dependencies]
7891
autocfg = "0.1"
7992

93+
[[bench]]
94+
name = "distributions"
95+
path = "benches/distributions.rs"
96+
required-features = ["small_rng"]
97+
98+
[[bench]]
99+
name = "generators"
100+
path = "benches/generators.rs"
101+
required-features = ["small_rng"]
102+
103+
[[bench]]
104+
name = "misc"
105+
path = "benches/misc.rs"
106+
required-features = ["small_rng"]
107+
108+
[[bench]]
109+
name = "seq"
110+
path = "benches/seq.rs"
111+
required-features = ["small_rng"]
112+
80113
[package.metadata.docs.rs]
81114
all-features = true
82115

README.md

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -84,41 +84,34 @@ pinned version of Rustc if you require compatibility with a specific version.
8484

8585
## Crate Features
8686

87-
Rand is built with the `std` and `getrandom` features enabled by default:
88-
89-
- `std` enables functionality dependent on the `std` lib and implies `alloc`
90-
and `getrandom`
91-
- `getrandom` is an optional crate, providing the code behind `rngs::OsRng`;
92-
the continued existance of this feature is not guaranteed so users are
93-
encouraged to specify `std` instead
94-
95-
The following optional features are available:
96-
97-
- `alloc` can be used instead of `std` to provide `Vec` and `Box`.
98-
- `log` enables some logging via the `log` crate.
99-
- `nightly` enables all unstable features (`simd_support`).
100-
- `serde1` enables serialization for some types, via Serde version 1.
101-
- `simd_support` enables uniform sampling of SIMD types (integers and floats).
102-
- `stdweb` enables support for `OsRng` on `wasm32-unknown-unknown` via `stdweb`
103-
combined with `cargo-web`.
104-
- `wasm-bindgen` enables support for `OsRng` on `wasm32-unknown-unknown` via
105-
[`wasm-bindgen`]
106-
107-
[`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen
108-
109-
`no_std` mode is activated by setting `default-features = false`; this removes
110-
functionality depending on `std`:
111-
112-
- `thread_rng()`, and `random()` are not available, as they require thread-local
113-
storage and an entropy source.
114-
- Since no external entropy is available, it is not possible to create
115-
generators with fresh seeds using the `FromEntropy` trait (user must provide
116-
a seed).
117-
- Several non-linear distributions distributions are unavailable since `exp`
118-
and `log` functions are not provided in `core`.
119-
- Large parts of the `seq`-uence module are unavailable, unless the `alloc`
120-
feature is used (several APIs and many implementations require `Vec`).
121-
87+
Rand is built with these features enabled by default:
88+
89+
- `std` enables functionality dependent on the `std` lib
90+
- `alloc` (implied by `std`) enables functionality requiring an allocator
91+
- `getrandom` (implied by `std`) is an optional dependency providing the code
92+
behind `rngs::OsRng`
93+
94+
Optionally, the following dependencies can be enabled:
95+
96+
- `log` enables logging via the `log` crate
97+
- `serde1` enables serialization for some types, via Serde version 1
98+
- `stdweb` implies `getrandom/stdweb` to enable
99+
`getrandom` support on `wasm32-unknown-unknown`
100+
- `wasm-bindgen` implies `getrandom/wasm-bindgen` to enable
101+
`getrandom` support on `wasm32-unknown-unknown`
102+
103+
Additionally, these features configure Rand:
104+
105+
- `small_rng` enables inclusion of the `SmallRng` PRNG
106+
- `nightly` enables all experimental features
107+
- `simd_support` (experimental) enables sampling of SIMD values
108+
(uniformly random SIMD integers and floats)
109+
110+
Rand supports limited functionality in `no_std` mode (enabled via
111+
`default-features = false`). In this case, `OsRng` and `from_entropy` are
112+
unavailable (unless `getrandom` is enabled), large parts of `seq` are
113+
unavailable (unless `alloc` is enabled), and `thread_rng` and `random` are
114+
unavailable.
122115

123116
# License
124117

benches/generators.rs

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// except according to those terms.
88

99
#![feature(test)]
10+
#![allow(non_snake_case)]
1011

1112
extern crate test;
1213
extern crate rand;
@@ -27,8 +28,8 @@ use rand::prelude::*;
2728
use rand::rngs::adapter::ReseedingRng;
2829
use rand::rngs::OsRng;
2930
use rand_isaac::{IsaacRng, Isaac64Rng};
30-
use rand_chacha::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
31-
use rand_hc::{Hc128Rng, Hc128Core};
31+
use rand_chacha::{ChaCha20Core, ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
32+
use rand_hc::{Hc128Rng};
3233
use rand_pcg::{Lcg64Xsh32, Mcg128Xsl64};
3334
use rand_xorshift::XorShiftRng;
3435
use rand_xoshiro::{Xoshiro256StarStar, Xoshiro256Plus, Xoshiro128StarStar,
@@ -165,46 +166,34 @@ init_gen!(init_isaac, IsaacRng);
165166
init_gen!(init_isaac64, Isaac64Rng);
166167
init_gen!(init_chacha, ChaCha20Rng);
167168

169+
const RESEEDING_BYTES_LEN: usize = 1024 * 1024;
170+
const RESEEDING_BENCH_N: u64 = 16;
168171

169-
const RESEEDING_THRESHOLD: u64 = 1024*1024*1024; // something high enough to get
170-
// deterministic measurements
171-
172-
#[bench]
173-
fn reseeding_hc128_bytes(b: &mut Bencher) {
174-
let mut rng = ReseedingRng::new(Hc128Core::from_entropy(),
175-
RESEEDING_THRESHOLD,
176-
OsRng);
177-
let mut buf = [0u8; BYTES_LEN];
178-
b.iter(|| {
179-
for _ in 0..RAND_BENCH_N {
180-
rng.fill_bytes(&mut buf);
181-
black_box(buf);
182-
}
183-
});
184-
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
185-
}
186-
187-
macro_rules! reseeding_uint {
188-
($fnn:ident, $ty:ty) => {
172+
macro_rules! reseeding_bytes {
173+
($fnn:ident, $thresh:expr) => {
189174
#[bench]
190175
fn $fnn(b: &mut Bencher) {
191-
let mut rng = ReseedingRng::new(Hc128Core::from_entropy(),
192-
RESEEDING_THRESHOLD,
176+
let mut rng = ReseedingRng::new(ChaCha20Core::from_entropy(),
177+
$thresh * 1024,
193178
OsRng);
179+
let mut buf = [0u8; RESEEDING_BYTES_LEN];
194180
b.iter(|| {
195-
let mut accum: $ty = 0;
196-
for _ in 0..RAND_BENCH_N {
197-
accum = accum.wrapping_add(rng.gen::<$ty>());
181+
for _ in 0..RESEEDING_BENCH_N {
182+
rng.fill_bytes(&mut buf);
183+
black_box(&buf);
198184
}
199-
accum
200185
});
201-
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
186+
b.bytes = RESEEDING_BYTES_LEN as u64 * RESEEDING_BENCH_N;
202187
}
203188
}
204189
}
205190

206-
reseeding_uint!(reseeding_hc128_u32, u32);
207-
reseeding_uint!(reseeding_hc128_u64, u64);
191+
reseeding_bytes!(reseeding_chacha20_4k, 4);
192+
reseeding_bytes!(reseeding_chacha20_16k, 16);
193+
reseeding_bytes!(reseeding_chacha20_32k, 32);
194+
reseeding_bytes!(reseeding_chacha20_64k, 64);
195+
reseeding_bytes!(reseeding_chacha20_256k, 256);
196+
reseeding_bytes!(reseeding_chacha20_1M, 1024);
208197

209198

210199
macro_rules! threadrng_uint {

rand_distr/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ appveyor = { repository = "rust-random/rand" }
2121
[dependencies]
2222
rand = { path = "..", version = ">=0.5, <=0.7" }
2323

24+
2425
[dev-dependencies]
26+
rand_pcg = { version = "0.1", path = "../rand_pcg" }
2527
# Histogram implementation for testing uniformity
2628
average = "0.9.2"

rand_distr/src/cauchy.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,30 +87,24 @@ mod test {
8787
}
8888

8989
#[test]
90-
fn test_cauchy_median() {
90+
fn test_cauchy_averages() {
91+
// NOTE: given that the variance and mean are undefined,
92+
// this test does not have any rigorous statistical meaning.
9193
let cauchy = Cauchy::new(10.0, 5.0).unwrap();
9294
let mut rng = crate::test::rng(123);
9395
let mut numbers: [f64; 1000] = [0.0; 1000];
96+
let mut sum = 0.0;
9497
for i in 0..1000 {
9598
numbers[i] = cauchy.sample(&mut rng);
99+
sum += numbers[i];
96100
}
97101
let median = median(&mut numbers);
98102
println!("Cauchy median: {}", median);
99-
assert!((median - 10.0).abs() < 0.5); // not 100% certain, but probable enough
100-
}
101-
102-
#[test]
103-
fn test_cauchy_mean() {
104-
let cauchy = Cauchy::new(10.0, 5.0).unwrap();
105-
let mut rng = crate::test::rng(123);
106-
let mut sum = 0.0f64;
107-
for _ in 0..1000 {
108-
sum += cauchy.sample(&mut rng);
109-
}
103+
assert!((median - 10.0).abs() < 0.4); // not 100% certain, but probable enough
110104
let mean = sum / 1000.0;
111105
println!("Cauchy mean: {}", mean);
112106
// for a Cauchy distribution the mean should not converge
113-
assert!((mean - 10.0).abs() > 0.5); // not 100% certain, but probable enough
107+
assert!((mean - 10.0).abs() > 0.4); // not 100% certain, but probable enough
114108
}
115109

116110
#[test]

rand_distr/src/exponential.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::utils::{ziggurat, Float};
3333
/// use rand::prelude::*;
3434
/// use rand_distr::Exp1;
3535
///
36-
/// let val: f64 = SmallRng::from_entropy().sample(Exp1);
36+
/// let val: f64 = thread_rng().sample(Exp1);
3737
/// println!("{}", val);
3838
/// ```
3939
#[derive(Clone, Copy, Debug)]

rand_distr/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,11 @@ mod test {
121121
// NOTE: Some distributions have tests checking only that samples can be
122122
// generated. This is redundant with vector and correctness tests.
123123

124-
use rand::{RngCore, SeedableRng, rngs::StdRng};
125-
126124
/// Construct a deterministic RNG with the given seed
127-
pub fn rng(seed: u64) -> impl RngCore {
128-
StdRng::seed_from_u64(seed)
125+
pub fn rng(seed: u64) -> impl rand::RngCore {
126+
// For tests, we want a statistically good, fast, reproducible RNG.
127+
// PCG32 will do fine, and will be easy to embed if we ever need to.
128+
const INC: u64 = 11634580027462260723;
129+
rand_pcg::Pcg32::new(seed, INC)
129130
}
130131
}

rand_distr/src/normal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::utils::{ziggurat, Float};
3131
/// use rand::prelude::*;
3232
/// use rand_distr::StandardNormal;
3333
///
34-
/// let val: f64 = SmallRng::from_entropy().sample(StandardNormal);
34+
/// let val: f64 = thread_rng().sample(StandardNormal);
3535
/// println!("{}", val);
3636
/// ```
3737
#[derive(Clone, Copy, Debug)]

rand_distr/src/pareto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::utils::Float;
1919
/// use rand::prelude::*;
2020
/// use rand_distr::Pareto;
2121
///
22-
/// let val: f64 = SmallRng::from_entropy().sample(Pareto::new(1., 2.).unwrap());
22+
/// let val: f64 = thread_rng().sample(Pareto::new(1., 2.).unwrap());
2323
/// println!("{}", val);
2424
/// ```
2525
#[derive(Clone, Copy, Debug)]

rand_distr/src/pert.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,13 @@ mod test {
118118
}
119119

120120
#[test]
121-
fn test_pert_vector() {
121+
fn value_stability() {
122122
let rng = crate::test::rng(860);
123123
let distr = Pert::new(2., 10., 3.).unwrap(); // mean = 4, var = 12/7
124124
let seq = distr.sample_iter(rng).take(5).collect::<Vec<f64>>();
125125
println!("seq: {:?}", seq);
126-
let expected = vec![3.945192480331639, 4.571769050527243,
127-
7.419819712922435, 4.049743197259167, 5.825644880531534];
126+
let expected = vec![4.631484136029422, 3.307201472321789,
127+
3.29995019556348, 3.66835483991721, 3.514246139933899];
128128
assert!(seq == expected);
129129
}
130130
}

rand_distr/src/triangular.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,13 @@ mod test {
111111
}
112112

113113
#[test]
114-
fn test_triangular_vector() {
114+
fn value_stability() {
115115
let rng = crate::test::rng(860);
116116
let distr = Triangular::new(2., 10., 3.).unwrap();
117117
let seq = distr.sample_iter(rng).take(5).collect::<Vec<f64>>();
118118
println!("seq: {:?}", seq);
119-
let expected = vec![4.941640229082449, 2.421447306833011,
120-
4.5964271605527385, 2.789763631136542, 4.8014432067978445];
119+
let expected = vec![5.74373257511361, 7.890059162791258,
120+
4.7256280652553455, 2.9474808121184077, 3.058301946314053];
121121
assert!(seq == expected);
122122
}
123123
}

rand_distr/src/unit_ball.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ mod tests {
5555
fn value_stability() {
5656
let mut rng = crate::test::rng(2);
5757
let expected = [
58-
[-0.42140140089381806, 0.4245276448803281, -0.7109276652167549],
59-
[0.6683277779168173, 0.12753134283863998, 0.6843687153674809],
60-
[-0.80397712218568, -0.0015797354643116712, 0.1588400395442835],
58+
[0.018035709265959987, -0.4348771383120438, -0.07982762085055706],
59+
[0.10588569388223945, -0.4734350111375454, -0.7392104908825501],
60+
[0.11060237642041049, -0.16065642822852677, -0.8444043930440075]
6161
];
6262
let samples: [[f64; 3]; 3] = [
6363
UnitBall.sample(&mut rng),

rand_distr/src/unit_circle.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ mod tests {
8585
fn value_stability() {
8686
let mut rng = crate::test::rng(2);
8787
let expected = [
88-
[-0.8032118336637037, 0.5956935036263119],
89-
[-0.4742919588505423, -0.880367615130018],
90-
[0.9297328981467168, 0.368234623716601],
88+
[-0.9965658683520504, -0.08280380447614634],
89+
[-0.9790853270389644, -0.20345004884984505],
90+
[-0.8449189758898707, 0.5348943112253227],
9191
];
9292
let samples: [[f64; 2]; 3] = [
9393
UnitCircle.sample(&mut rng),

0 commit comments

Comments
 (0)