Merge pull request #11 from AFLplusplus/fix-default-prng
impl Default for rngs with a decent seed
This commit is contained in:
commit
776349eaa7
@ -11,13 +11,13 @@ pub type StdRand = RomuTrioRand;
|
|||||||
|
|
||||||
/// Ways to get random around here
|
/// Ways to get random around here
|
||||||
pub trait Rand: Debug + Serialize + DeserializeOwned {
|
pub trait Rand: Debug + Serialize + DeserializeOwned {
|
||||||
// Sets the seed of this Rand
|
/// Sets the seed of this Rand
|
||||||
fn set_seed(&mut self, seed: u64);
|
fn set_seed(&mut self, seed: u64);
|
||||||
|
|
||||||
// Gets the next 64 bit value
|
/// Gets the next 64 bit value
|
||||||
fn next(&mut self) -> u64;
|
fn next(&mut self) -> u64;
|
||||||
|
|
||||||
// Gets a value below the given 64 bit val (inclusive)
|
/// Gets a value below the given 64 bit val (inclusive)
|
||||||
fn below(&mut self, upper_bound_excl: u64) -> u64 {
|
fn below(&mut self, upper_bound_excl: u64) -> u64 {
|
||||||
if upper_bound_excl <= 1 {
|
if upper_bound_excl <= 1 {
|
||||||
return 0;
|
return 0;
|
||||||
@ -39,7 +39,7 @@ pub trait Rand: Debug + Serialize + DeserializeOwned {
|
|||||||
unbiased_rnd % upper_bound_excl
|
unbiased_rnd % upper_bound_excl
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a value between the given lower bound (inclusive) and upper bound (inclusive)
|
/// Gets a value between the given lower bound (inclusive) and upper bound (inclusive)
|
||||||
fn between(&mut self, lower_bound_incl: u64, upper_bound_incl: u64) -> u64 {
|
fn between(&mut self, lower_bound_incl: u64, upper_bound_incl: u64) -> u64 {
|
||||||
debug_assert!(lower_bound_incl <= upper_bound_incl);
|
debug_assert!(lower_bound_incl <= upper_bound_incl);
|
||||||
lower_bound_incl + self.below(upper_bound_incl - lower_bound_incl + 1)
|
lower_bound_incl + self.below(upper_bound_incl - lower_bound_incl + 1)
|
||||||
@ -54,16 +54,16 @@ where
|
|||||||
/// Get the hold RefCell Rand instance
|
/// Get the hold RefCell Rand instance
|
||||||
fn rand(&self) -> &RefCell<R>;
|
fn rand(&self) -> &RefCell<R>;
|
||||||
|
|
||||||
// Gets the next 64 bit value
|
/// Gets the next 64 bit value
|
||||||
fn rand_next(&mut self) -> u64 {
|
fn rand_next(&mut self) -> u64 {
|
||||||
self.rand().borrow_mut().next()
|
self.rand().borrow_mut().next()
|
||||||
}
|
}
|
||||||
// Gets a value below the given 64 bit val (inclusive)
|
/// Gets a value below the given 64 bit val (inclusive)
|
||||||
fn rand_below(&mut self, upper_bound_excl: u64) -> u64 {
|
fn rand_below(&mut self, upper_bound_excl: u64) -> u64 {
|
||||||
self.rand().borrow_mut().below(upper_bound_excl)
|
self.rand().borrow_mut().below(upper_bound_excl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a value between the given lower bound (inclusive) and upper bound (inclusive)
|
/// Gets a value between the given lower bound (inclusive) and upper bound (inclusive)
|
||||||
fn rand_between(&mut self, lower_bound_incl: u64, upper_bound_incl: u64) -> u64 {
|
fn rand_between(&mut self, lower_bound_incl: u64, upper_bound_incl: u64) -> u64 {
|
||||||
self.rand()
|
self.rand()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
@ -71,7 +71,58 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper macro for deriving Default
|
||||||
|
macro_rules! default_rand {
|
||||||
|
($rand: ty) => {
|
||||||
|
/// A default RNG will produce a deterministic and reproducible stream of random numbers.
|
||||||
|
/// Use [`RandomSeed::with_random_seed`] to generate unique RNG seeded from some source of
|
||||||
|
/// randomness.
|
||||||
|
impl core::default::Default for $rand {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(DEFAULT_SEED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derive Default by calling `new(DEFAULT_SEED)` on each of the following Rand types.
|
||||||
|
default_rand!(Xoshiro256StarRand);
|
||||||
|
default_rand!(XorShift64Rand);
|
||||||
|
default_rand!(Lehmer64Rand);
|
||||||
|
default_rand!(RomuTrioRand);
|
||||||
|
default_rand!(RomuDuoJrRand);
|
||||||
|
|
||||||
|
/// Initialize Rand types from a source of randomness.
|
||||||
|
///
|
||||||
|
/// Default implementations are provided with the "std" feature enabled, using system time in
|
||||||
|
/// nanoseconds as the initial seed.
|
||||||
|
pub trait RandomSeed: Rand + Default {
|
||||||
|
fn with_random_seed() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper macro to impl RandomSeed
|
||||||
|
macro_rules! impl_randomseed {
|
||||||
|
($rand: ty) => {
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl RandomSeed for $rand {
|
||||||
|
/// Creates a rand instance, pre-seeded with the current time in nanoseconds.
|
||||||
|
fn with_random_seed() -> Self {
|
||||||
|
let mut rng = Self::default();
|
||||||
|
rng.set_seed(current_nanos());
|
||||||
|
rng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_randomseed!(Xoshiro256StarRand);
|
||||||
|
impl_randomseed!(XorShift64Rand);
|
||||||
|
impl_randomseed!(Lehmer64Rand);
|
||||||
|
impl_randomseed!(RomuTrioRand);
|
||||||
|
impl_randomseed!(RomuDuoJrRand);
|
||||||
|
|
||||||
const HASH_CONST: u64 = 0xa5b35705;
|
const HASH_CONST: u64 = 0xa5b35705;
|
||||||
|
const DEFAULT_SEED: u64 = 0x54d3a3130133750b;
|
||||||
|
|
||||||
/// Current time
|
/// Current time
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
@ -79,6 +130,7 @@ const HASH_CONST: u64 = 0xa5b35705;
|
|||||||
pub fn current_time() -> time::Duration {
|
pub fn current_time() -> time::Duration {
|
||||||
SystemTime::now().duration_since(UNIX_EPOCH).unwrap()
|
SystemTime::now().duration_since(UNIX_EPOCH).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Current time (fixed fallback for no_std)
|
/// Current time (fixed fallback for no_std)
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -98,12 +150,24 @@ pub fn current_nanos() -> u64 {
|
|||||||
.as_nanos() as u64
|
.as_nanos() as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
/// Gets current milliseconds since UNIX_EPOCH
|
||||||
|
pub fn current_milliseconds() -> u64 {
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_millis() as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "std"))]
|
||||||
|
pub fn current_milliseconds() -> u64 {
|
||||||
|
1000
|
||||||
|
}
|
||||||
|
|
||||||
/// XXH3 Based, hopefully speedy, rnd implementation
|
/// XXH3 Based, hopefully speedy, rnd implementation
|
||||||
///
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
|
||||||
pub struct Xoshiro256StarRand {
|
pub struct Xoshiro256StarRand {
|
||||||
rand_seed: [u64; 4],
|
rand_seed: [u64; 4],
|
||||||
seeded: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rand for Xoshiro256StarRand {
|
impl Rand for Xoshiro256StarRand {
|
||||||
@ -112,8 +176,6 @@ impl Rand for Xoshiro256StarRand {
|
|||||||
self.rand_seed[1] = self.rand_seed[0] ^ 0x1234567890abcdef;
|
self.rand_seed[1] = self.rand_seed[0] ^ 0x1234567890abcdef;
|
||||||
self.rand_seed[2] = self.rand_seed[0] & 0x0123456789abcdef;
|
self.rand_seed[2] = self.rand_seed[0] & 0x0123456789abcdef;
|
||||||
self.rand_seed[3] = self.rand_seed[0] | 0x01abcde43f567908;
|
self.rand_seed[3] = self.rand_seed[0] | 0x01abcde43f567908;
|
||||||
|
|
||||||
self.seeded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -140,31 +202,21 @@ impl Rand for Xoshiro256StarRand {
|
|||||||
impl Xoshiro256StarRand {
|
impl Xoshiro256StarRand {
|
||||||
/// Creates a new Xoshiro rand with the given seed
|
/// Creates a new Xoshiro rand with the given seed
|
||||||
pub fn new(seed: u64) -> Self {
|
pub fn new(seed: u64) -> Self {
|
||||||
let mut ret: Self = Default::default();
|
let mut rand = Self { rand_seed: [0; 4] };
|
||||||
ret.set_seed(seed); // TODO: Proper random seed?
|
rand.set_seed(seed); // TODO: Proper random seed?
|
||||||
ret
|
rand
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a rand instance, pre-seeded with the current time in nanoseconds.
|
|
||||||
/// Needs stdlib timer
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn preseeded() -> Self {
|
|
||||||
Self::new(current_nanos())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XXH3 Based, hopefully speedy, rnd implementation
|
/// XXH3 Based, hopefully speedy, rnd implementation
|
||||||
///
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
|
||||||
pub struct XorShift64Rand {
|
pub struct XorShift64Rand {
|
||||||
rand_seed: u64,
|
rand_seed: u64,
|
||||||
seeded: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rand for XorShift64Rand {
|
impl Rand for XorShift64Rand {
|
||||||
fn set_seed(&mut self, seed: u64) {
|
fn set_seed(&mut self, seed: u64) {
|
||||||
self.rand_seed = seed ^ 0x1234567890abcdef;
|
self.rand_seed = seed ^ 0x1234567890abcdef;
|
||||||
self.seeded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -181,31 +233,21 @@ impl Rand for XorShift64Rand {
|
|||||||
impl XorShift64Rand {
|
impl XorShift64Rand {
|
||||||
/// Creates a new Xoshiro rand with the given seed
|
/// Creates a new Xoshiro rand with the given seed
|
||||||
pub fn new(seed: u64) -> Self {
|
pub fn new(seed: u64) -> Self {
|
||||||
let mut ret: Self = Default::default();
|
let mut ret: Self = Self { rand_seed: 0 };
|
||||||
ret.set_seed(seed); // TODO: Proper random seed?
|
ret.set_seed(seed); // TODO: Proper random seed?
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a rand instance, pre-seeded with the current time in nanoseconds.
|
|
||||||
/// Needs stdlib timer
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn preseeded() -> Self {
|
|
||||||
Self::new(current_nanos())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// XXH3 Based, hopefully speedy, rnd implementation
|
/// XXH3 Based, hopefully speedy, rnd implementation
|
||||||
///
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
|
||||||
pub struct Lehmer64Rand {
|
pub struct Lehmer64Rand {
|
||||||
rand_seed: u128,
|
rand_seed: u128,
|
||||||
seeded: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rand for Lehmer64Rand {
|
impl Rand for Lehmer64Rand {
|
||||||
fn set_seed(&mut self, seed: u64) {
|
fn set_seed(&mut self, seed: u64) {
|
||||||
self.rand_seed = (seed as u128) ^ 0x1234567890abcdef;
|
self.rand_seed = (seed as u128) ^ 0x1234567890abcdef;
|
||||||
self.seeded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -218,22 +260,15 @@ impl Rand for Lehmer64Rand {
|
|||||||
impl Lehmer64Rand {
|
impl Lehmer64Rand {
|
||||||
/// Creates a new Lehmer rand with the given seed
|
/// Creates a new Lehmer rand with the given seed
|
||||||
pub fn new(seed: u64) -> Self {
|
pub fn new(seed: u64) -> Self {
|
||||||
let mut ret: Self = Default::default();
|
let mut ret: Self = Self { rand_seed: 0 };
|
||||||
ret.set_seed(seed);
|
ret.set_seed(seed);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a rand instance, pre-seeded with the current time in nanoseconds.
|
|
||||||
/// Needs stdlib timer
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn preseeded() -> Self {
|
|
||||||
Self::new(current_nanos())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extremely quick rand implementation
|
/// Extremely quick rand implementation
|
||||||
/// see <https://arxiv.org/pdf/2002.11331.pdf>
|
/// see <https://arxiv.org/pdf/2002.11331.pdf>
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct RomuTrioRand {
|
pub struct RomuTrioRand {
|
||||||
x_state: u64,
|
x_state: u64,
|
||||||
y_state: u64,
|
y_state: u64,
|
||||||
@ -242,17 +277,14 @@ pub struct RomuTrioRand {
|
|||||||
|
|
||||||
impl RomuTrioRand {
|
impl RomuTrioRand {
|
||||||
pub fn new(seed: u64) -> Self {
|
pub fn new(seed: u64) -> Self {
|
||||||
let mut rand = Self::default();
|
let mut rand = Self {
|
||||||
|
x_state: 0,
|
||||||
|
y_state: 0,
|
||||||
|
z_state: 0,
|
||||||
|
};
|
||||||
rand.set_seed(seed);
|
rand.set_seed(seed);
|
||||||
rand
|
rand
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a rand instance, pre-seeded with the current time in nanoseconds.
|
|
||||||
/// Needs stdlib timer
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn preseeded() -> Self {
|
|
||||||
Self::new(current_nanos())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rand for RomuTrioRand {
|
impl Rand for RomuTrioRand {
|
||||||
@ -275,7 +307,7 @@ impl Rand for RomuTrioRand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// see <https://arxiv.org/pdf/2002.11331.pdf>
|
/// see <https://arxiv.org/pdf/2002.11331.pdf>
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct RomuDuoJrRand {
|
pub struct RomuDuoJrRand {
|
||||||
x_state: u64,
|
x_state: u64,
|
||||||
y_state: u64,
|
y_state: u64,
|
||||||
@ -283,17 +315,13 @@ pub struct RomuDuoJrRand {
|
|||||||
|
|
||||||
impl RomuDuoJrRand {
|
impl RomuDuoJrRand {
|
||||||
pub fn new(seed: u64) -> Self {
|
pub fn new(seed: u64) -> Self {
|
||||||
let mut rand = Self::default();
|
let mut rand = Self {
|
||||||
|
x_state: 0,
|
||||||
|
y_state: 0,
|
||||||
|
};
|
||||||
rand.set_seed(seed);
|
rand.set_seed(seed);
|
||||||
rand
|
rand
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a rand instance, pre-seeded with the current time in nanoseconds.
|
|
||||||
/// Needs stdlib timer
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn preseeded() -> Self {
|
|
||||||
Self::new(current_nanos())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rand for RomuDuoJrRand {
|
impl Rand for RomuDuoJrRand {
|
||||||
@ -311,21 +339,6 @@ impl Rand for RomuDuoJrRand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current milliseconds
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub fn current_milliseconds() -> u64 {
|
|
||||||
SystemTime::now()
|
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.unwrap()
|
|
||||||
.as_millis() as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a fixed value of 1k for no_std (for now)
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
pub fn current_milliseconds() -> u64 {
|
|
||||||
1000
|
|
||||||
}
|
|
||||||
|
|
||||||
/// fake rand, for testing purposes
|
/// fake rand, for testing purposes
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
@ -369,9 +382,13 @@ mod tests {
|
|||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rand_preseeded() {
|
fn with_random_seed() {
|
||||||
|
use crate::utils::RandomSeed;
|
||||||
|
|
||||||
let mut rand_fixed = StdRand::new(0);
|
let mut rand_fixed = StdRand::new(0);
|
||||||
let mut rand = StdRand::preseeded();
|
let mut rand = StdRand::with_random_seed();
|
||||||
|
|
||||||
|
for _ in 0..10000 {
|
||||||
assert_ne!(rand.next(), rand_fixed.next());
|
assert_ne!(rand.next(), rand_fixed.next());
|
||||||
assert_ne!(rand.next(), rand.next());
|
assert_ne!(rand.next(), rand.next());
|
||||||
assert!(rand.below(100) < 100);
|
assert!(rand.below(100) < 100);
|
||||||
@ -380,3 +397,4 @@ mod tests {
|
|||||||
assert!(rand.between(11, 20) > 10);
|
assert!(rand.between(11, 20) > 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user