1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
/*
VAX MTH$RANDOM reimplementation by Radim Kolar <hsn@sendmail.cz> 2024
https://gitlab.com/hsn10/vaxmth
This is free and unencumbered software released into the public domain.
SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#![forbid(unsafe_code)]
#![forbid(missing_docs)]
#![forbid(arithmetic_overflow)]
#![allow(non_snake_case)]
//! LCG69096 / VAX MTH$RANDOM is pseudo random number generator.
//!
//! Generator period is 2^32 for LCG and 2^30 for MCG variant.
//! Generator is named after multiplier coeficient A = 69069.
/**
multiplier A coeficient 69069 = 3 * 7 * 11 * 13 * 23
Used for multiplying seed value.
This palindromically convoluted multiplier is easy to remember
and has a nearly cubic lattice for moduli 2 ^ 32, 2 ^ 35, 2 ^ 36.
*/
pub const A: u32 = 69069;
/**
modulo M coeficient 2^32
Used for modulo operation final result.
*/
const M: u64 = 0x1_0000_0000;
/**
VAX MTH$RANDOM number generator. Its same as LCG69069.
<https://oeis.org/A096552>
*/
pub struct RANDOM(u32);
impl RANDOM {
/**
increment C coeficient 1
Value is added after mutiplication.
*/
const C: u32 = 1;
/**
Default seed.
Default seed in
*/
pub const SEED: u32 = 0;
/**
Creates new MTH$RANDOM generator with default seed.
*/
pub fn new() -> Self {
Self(Self::SEED)
}
/**
Creates new MTH$RANDOM generator with provided seed.
*/
pub fn seed(seed: u32) -> Self {
Self(seed)
}
/**
Get next unsigned 32-bit integer from generator.
Returned value spans entire 32-bit unsigned integer range.
*/
pub fn next(&mut self) -> u32 {
self.0 = self.0.wrapping_mul(A).wrapping_add(Self::C);
self.0
}
/**
Get next double value from generator.
Returned value is in range zero inclusive to 1.0 exclusive.
*/
pub fn nextDouble(&mut self) -> f64 {
self.next() as f64 / M as f64
}
}
/**
Multiplicative congruential pseudo-random number generator.
69069 parameter proposed by George Marsaglia as
a "candidate for the best of all multipliers".
Period 2^30
<https://oeis.org/A096551>
*/
pub struct MCG69069(u32);
impl MCG69069 {
/**
Initial MCG seed is 1
*/
pub const SEED: u32 = 1;
/**
Create instance of MCG69069 with initial seed.
*/
pub fn new() -> Self {
Self(Self::SEED)
}
/**
Create instance of MCG69069 with specified seed.
Seed can't be zero.
*/
pub fn seed(seed: u32) -> Self {
assert! ( seed !=0, "MCG requires non zero seed." );
Self(seed)
}
/**
Get next unsigned 32-bit integer from generator.
Returned value spans entire 32-bit unsigned integer range.
*/
pub fn next(&mut self) -> u32 {
self.0 = self.0.wrapping_mul(A);
self.0
}
/**
Get next double value from generator.
Returned value is in range zero inclusive to 1.0 exclusive.
*/
pub fn nextDouble(&mut self) -> f64 {
self.next() as f64 / M as f64
}
}
/**
LCG variant of MCG69069.
*/
pub struct LCG69069(u32);
impl LCG69069 {
/**
Initial LCG69069 seed is zero
*/
pub const SEED: u32 = 0;
/**
Increment coeficient for LCG variant is 1
*/
pub const C: u32 = 1;
/**
Create instance of LCG69069 with initial seed.
*/
pub fn new() -> Self {
Self(Self::SEED)
}
/**
Create instance of LCG69069 with supplied seed.
*/
pub fn seed(seed: u32) -> Self {
Self(seed)
}
/**
Get next unsigned 32-bit integer from generator.
Returned value spans entire 32-bit unsigned integer range.
*/
pub fn next(&mut self) -> u32 {
self.0 = self.0.wrapping_mul(A).wrapping_add(Self::C);
self.0
}
/**
Get next double value from generator.
Returned value is in range zero inclusive to 1.0 exclusive.
*/
pub fn nextDouble(&mut self) -> f64 {
self.next() as f64 / M as f64
}
}
#[cfg(test)]
#[path="seq_test.rs"]
mod tests_vax;
#[cfg(test)]
#[path="seq_test_mcg.rs"]
mod tests_mcg;
#[cfg(test)]
#[path="seq_test_lcg.rs"]
mod tests_lcg;
#[cfg(test)]
#[path="period_test.rs"]
mod period;
#[cfg(test)]
#[path="const_test.rs"]
mod consts;
#[cfg(test)]
#[path="assert_test.rs"]
mod assert;