diff --git a/Cargo.toml b/Cargo.toml
index 5390fd9d970..616a3cdd35f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,6 +32,7 @@ members = ["rand_core", "rand_isaac", "rand_chacha", "rand_hc128", "rand_pcg", "
[dependencies]
rand_core = { path = "rand_core", version = "0.3", default-features = false }
+rand_pcg = { path = "rand_pcg", version = "0.1" }
# only for deprecations and benches:
rand_isaac = { path = "rand_isaac", version = "0.1" }
rand_chacha = { path = "rand_chacha", version = "0.1" }
diff --git a/benches/generators.rs b/benches/generators.rs
index 977a1beed78..608c64eac01 100644
--- a/benches/generators.rs
+++ b/benches/generators.rs
@@ -13,6 +13,7 @@ extern crate rand;
extern crate rand_isaac;
extern crate rand_chacha;
extern crate rand_hc128;
+extern crate rand_pcg;
extern crate rand_xorshift;
const RAND_BENCH_N: u64 = 1000;
@@ -27,6 +28,7 @@ use rand::rngs::{OsRng, JitterRng, EntropyRng};
use rand_isaac::{IsaacRng, Isaac64Rng};
use rand_chacha::ChaChaRng;
use rand_hc128::{Hc128Rng, Hc128Core};
+use rand_pcg::{Lcg64Xsh32, Mcg128Xsl64};
use rand_xorshift::XorShiftRng;
macro_rules! gen_bytes {
@@ -47,6 +49,8 @@ macro_rules! gen_bytes {
}
gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy());
+gen_bytes!(gen_bytes_lcg64_xsh32, Lcg64Xsh32::from_entropy());
+gen_bytes!(gen_bytes_mcg128_xsh64, Mcg128Xsl64::from_entropy());
gen_bytes!(gen_bytes_chacha20, ChaChaRng::from_entropy());
gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy());
gen_bytes!(gen_bytes_isaac, IsaacRng::from_entropy());
@@ -73,6 +77,8 @@ macro_rules! gen_uint {
}
gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy());
+gen_uint!(gen_u32_lcg64_xsh32, u32, Lcg64Xsh32::from_entropy());
+gen_uint!(gen_u32_mcg128_xsh64, u32, Mcg128Xsl64::from_entropy());
gen_uint!(gen_u32_chacha20, u32, ChaChaRng::from_entropy());
gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy());
gen_uint!(gen_u32_isaac, u32, IsaacRng::from_entropy());
@@ -82,6 +88,8 @@ gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
gen_uint!(gen_u32_os, u32, OsRng::new().unwrap());
gen_uint!(gen_u64_xorshift, u64, XorShiftRng::from_entropy());
+gen_uint!(gen_u64_lcg64_xsh32, u64, Lcg64Xsh32::from_entropy());
+gen_uint!(gen_u64_mcg128_xsh64, u64, Mcg128Xsl64::from_entropy());
gen_uint!(gen_u64_chacha20, u64, ChaChaRng::from_entropy());
gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy());
gen_uint!(gen_u64_isaac, u64, IsaacRng::from_entropy());
@@ -115,6 +123,8 @@ macro_rules! init_gen {
}
init_gen!(init_xorshift, XorShiftRng);
+init_gen!(init_lcg64_xsh32, Lcg64Xsh32);
+init_gen!(init_mcg128_xsh64, Mcg128Xsl64);
init_gen!(init_hc128, Hc128Rng);
init_gen!(init_isaac, IsaacRng);
init_gen!(init_isaac64, Isaac64Rng);
diff --git a/src/lib.rs b/src/lib.rs
index 13f52153367..19dbd639cbf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -245,6 +245,7 @@ extern crate rand_core;
extern crate rand_isaac; // only for deprecations
extern crate rand_chacha; // only for deprecations
extern crate rand_hc128;
+extern crate rand_pcg;
extern crate rand_xorshift;
#[cfg(feature = "log")] #[macro_use] extern crate log;
diff --git a/src/prng/mod.rs b/src/prng/mod.rs
index 7c8c69dbb10..672b1264a6b 100644
--- a/src/prng/mod.rs
+++ b/src/prng/mod.rs
@@ -45,18 +45,18 @@
//!
//! | name | full name | performance | memory | quality | period | features |
//! |------|-----------|-------------|--------|---------|--------|----------|
-//! | [`XorShiftRng`] | Xorshift 32/128 | ★★★☆☆ | 16 bytes | ★☆☆☆☆ | `u32` * 2128 - 1 | — |
+//! | [`Pcg32`] | PCG XSH RR 64/32 (LCG) | ★★★☆☆ | 16 bytes | ★★★☆☆ | `u32` * 264 | — |
+//! | [`Pcg64Mcg`] | PCG XSL 128/64 (MCG) | ★★★★☆ | 16 bytes | ★★★☆☆ | `u64` * 2126 | — |
+//! | [`XorShiftRng`] | Xorshift 32/128 | ★★★★☆ | 16 bytes | ★☆☆☆☆ | `u32` * 2128 - 1 | — |
//!
// Quality stars [not rendered in documentation]:
-// 5. reserved for crypto-level (e.g. ChaCha8, ISAAC)
-// 4. good performance on TestU01 and PractRand, good theory
-// (e.g. PCG, truncated Xorshift*)
-// 3. good performance on TestU01 and PractRand, but "falling through the
-// cracks" or insufficient theory (e.g. SFC, Xoshiro)
-// 2. imperfect performance on tests or other limiting properties, but not
-// terrible (e.g. Xoroshiro128+)
+// 5. proven cryptographic quality (e.g. ChaCha20)
+// 4. potentially cryptographic, but low margin or lack of theory (e.g. ChaCha8, ISAAC)
+// 3. good performance on TestU01 and PractRand, good theory
+// 2. imperfect performance on tests or other limiting properties, or
+// insufficient theory, but not terrible
// 1. clear deficiencies in test results, cycle length, theory, or other
-// properties (e.g. Xorshift)
+// properties
//
// Performance stars [not rendered in documentation]:
// Meant to give an indication of relative performance. Roughly follows a log
@@ -297,6 +297,8 @@
//! [`rngs` module]: ../rngs/index.html
//! [basic PRNGs]: #basic-pseudo-random-number-generators-prngs
//! [CSPRNGs]: #cryptographically-secure-pseudo-random-number-generators-csprngs
+//! [`Pcg32`]: ../../rand_pcg/type.Pcg32.html
+//! [`Pcg64Mcg`]: ../../rand_pcg/type.Pcg64Mcg.html
//! [`XorShiftRng`]: ../../rand_xorshift/struct.XorShiftRng.html
//! [`ChaChaRng`]: ../../rand_chacha/struct.ChaChaRng.html
//! [`Hc128Rng`]: ../../rand_hc128/struct.Hc128Rng.html
diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs
index 6888517d98e..70c45069827 100644
--- a/src/rngs/mod.rs
+++ b/src/rngs/mod.rs
@@ -48,9 +48,6 @@
//!
//! - [`SmallRng`] is a PRNG chosen for low memory usage, high performance and
//! good statistical quality.
-//! The current algorithm (plain Xorshift) unfortunately performs
-//! poorly in statistical quality test suites (TestU01 and PractRand) and will
-//! be replaced in the next major release.
//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security
//! (based on reviews, maturity and usage). The current algorithm is HC-128,
//! which is one of the recommendations by ECRYPT's eSTREAM project.
diff --git a/src/rngs/small.rs b/src/rngs/small.rs
index 8197a64f7ac..c7b28fce702 100644
--- a/src/rngs/small.rs
+++ b/src/rngs/small.rs
@@ -9,7 +9,11 @@
//! A small fast RNG
use {RngCore, SeedableRng, Error};
-use ::rand_xorshift::XorShiftRng;
+
+#[cfg(all(rust_1_26, target_pointer_width = "64"))]
+type Rng = ::rand_pcg::Pcg64Mcg;
+#[cfg(not(all(rust_1_26, target_pointer_width = "64")))]
+type Rng = ::rand_pcg::Pcg32;
/// An RNG recommended when small state, cheap initialization and good
/// performance are required. The PRNG algorithm in `SmallRng` is chosen to be
@@ -20,9 +24,11 @@ use ::rand_xorshift::XorShiftRng;
/// future library versions may use a different internal generator with
/// different output. Further, this generator may not be portable and can
/// produce different output depending on the architecture. If you require
-/// reproducible output, use a named RNG, for example [`XorShiftRng`].
+/// reproducible output, use a named RNG. Refer to the documentation on the
+/// [`prng` module](../prng/index.html).
///
-/// The current algorithm used on all platforms is [Xorshift].
+/// The current algorithm is [`Pcg64Mcg`] on 64-bit platforms with Rust version
+/// 1.26 and later, or [`Pcg32`] otherwise.
///
/// # Examples
///
@@ -61,10 +67,10 @@ use ::rand_xorshift::XorShiftRng;
/// [`FromEntropy`]: ../trait.FromEntropy.html
/// [`StdRng`]: struct.StdRng.html
/// [`thread_rng`]: ../fn.thread_rng.html
-/// [Xorshift]: ../../rand_xorshift/struct.XorShiftRng.html
-/// [`XorShiftRng`]: ../../rand_xorshift/struct.XorShiftRng.html
+/// [`Pcg64Mcg`]: https://docs.rs/rand_pcg/0.1.0/rand_pcg/type.Pcg64Mcg.html
+/// [`Pcg32`]: https://docs.rs/rand_pcg/0.1.0/rand_pcg/type.Pcg32.html
#[derive(Clone, Debug)]
-pub struct SmallRng(XorShiftRng);
+pub struct SmallRng(Rng);
impl RngCore for SmallRng {
#[inline(always)]
@@ -87,13 +93,13 @@ impl RngCore for SmallRng {
}
impl SeedableRng for SmallRng {
- type Seed = ::Seed;
+ type Seed = ::Seed;
fn from_seed(seed: Self::Seed) -> Self {
- SmallRng(XorShiftRng::from_seed(seed))
+ SmallRng(Rng::from_seed(seed))
}
fn from_rng(rng: R) -> Result {
- XorShiftRng::from_rng(rng).map(SmallRng)
+ Rng::from_rng(rng).map(SmallRng)
}
}
diff --git a/src/seq/mod.rs b/src/seq/mod.rs
index 89d2417d666..99596028a63 100644
--- a/src/seq/mod.rs
+++ b/src/seq/mod.rs
@@ -512,7 +512,7 @@ pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) ->
mod test {
use super::*;
#[cfg(feature = "alloc")] use {Rng, SeedableRng};
- #[cfg(feature = "alloc")] use ::rand_xorshift::XorShiftRng;
+ #[cfg(feature = "alloc")] use rngs::SmallRng;
#[cfg(all(feature="alloc", not(feature="std")))]
use alloc::vec::Vec;
@@ -753,7 +753,7 @@ mod test {
#[cfg(feature = "alloc")]
#[allow(deprecated)]
fn test_sample_slice() {
- let xor_rng = XorShiftRng::from_seed;
+ let seeded_rng = SmallRng::from_seed;
let mut r = ::test::rng(403);
@@ -764,16 +764,16 @@ mod test {
r.fill(&mut seed);
// assert the basics work
- let regular = index::sample(&mut xor_rng(seed), length, amount);
+ let regular = index::sample(&mut seeded_rng(seed), length, amount);
assert_eq!(regular.len(), amount);
assert!(regular.iter().all(|e| e < length));
// also test that sampling the slice works
let vec: Vec = (0..(length as u32)).collect();
- let result = sample_slice(&mut xor_rng(seed), &vec, amount);
+ let result = sample_slice(&mut seeded_rng(seed), &vec, amount);
assert_eq!(result, regular.iter().map(|i| i as u32).collect::>());
- let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
+ let result = sample_slice_ref(&mut seeded_rng(seed), &vec, amount);
assert!(result.iter().zip(regular.iter()).all(|(i,j)| **i == j as u32));
}
}