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
///```rust
///use doe::*;
///let lcg = LCG::new();
///for _ in 0..10000{
///   let data = lcg.random_in_range(1..=20).to_string().push_back("\n");
///   fs::fs::append_data_to_file("doe.txt", data).unwrap();
///}
/// ```
#[allow(warnings)]
pub mod rand {
    /// A Linear Congruential Generator (LCG) is a simple type of random number generator
    /// that produces a sequence of pseudo-random numbers based on a linear recurrence relation.
    #[derive(Debug, Clone, Default)]
    pub struct LCG {
        seed: u128,
        a: u128,
        c: u128,
        m: u128,
    }

    impl LCG {
        /// Creates a new LCG instance with the specified initial seed is timestamp as nanoseconds.
        ///
        /// ```rust
        ///use doe::*;
        ///let lcg = LCG::new();
        ///for _ in 0..10000{
        ///    let data = lcg.random_in_range(1..=20).to_string().push_back("\n");
        ///    fs::fs::append_data_to_file("doe.txt", data).unwrap();
        ///}
        /// ```
        /// # Returns
        ///
        /// A new `LCG` instance with the specified seed and default constants.
        pub fn new() -> LCG {
            let seed = std::time::SystemTime::now()
                .duration_since(std::time::SystemTime::UNIX_EPOCH)
                .unwrap_or_default()
                .as_nanos();
            Self::init(seed, 1664525, 1013904223, 2u128.pow(32))
        }
        ///random_in_range
        /// ```rust
        ///use doe::*;  
        ///let lcg = LCG::new();
        ///for _ in 0..10000{
        ///    lcg.random_in_range(-30..30).dprintln();  
        ///}
        /// ```
        ///
        pub fn random_in_range(&self, range: impl std::ops::RangeBounds<i128>) -> i128 {
            let min = match range.start_bound() {
                std::ops::Bound::Included(v) => *v,
                std::ops::Bound::Excluded(v) => *v,
                std::ops::Bound::Unbounded => 0,
            };

            let max = match range.end_bound() {
                std::ops::Bound::Included(v) => *v + 1,
                std::ops::Bound::Excluded(v) => *v,
                std::ops::Bound::Unbounded => i128::MAX,
            };
            let random = Self::new().random();
            let sub = (max - min) as f64;
            f64::floor(random * sub) as i128 + min
        }
        ///random_in_range_f64
        ///```rust
        ///use doe::*;  
        ///let lcg = LCG::new();
        ///for _ in 0..10000{
        ///    lcg.random_in_range_f64(-30.0..30.0).dprintln();  
        ///}
        /// ```
        pub fn random_in_range_f64(&self, range: impl std::ops::RangeBounds<f64>) -> f64 {
            let min = match range.start_bound() {
                std::ops::Bound::Included(v) => *v,
                std::ops::Bound::Excluded(v) => *v,
                std::ops::Bound::Unbounded => 0.0,
            };

            let max = match range.end_bound() {
                std::ops::Bound::Included(v) => *v,
                std::ops::Bound::Excluded(v) => *v,
                std::ops::Bound::Unbounded => f64::MAX,
            };

            let random = Self::new().random();
            let sub = max - min;
            (random * sub) + min
        }

        /// Creates a new LCG instance with the specified initial seed value.
        ///
        /// # Arguments
        ///
        /// * `seed` - The initial seed value for the LCG.
        ///
        /// # Returns
        ///
        /// A new `LCG` instance with the specified seed and default constants.
        pub fn new_with_seed(seed: u128) -> LCG {
            Self::init(seed, 1664525, 1013904223, 2u128.pow(32))
        }

        /// Creates a new LCG instance with the specified initial seed value and constants.
        ///
        /// # Arguments
        ///
        /// * `seed` - The initial seed value for the LCG.
        /// * `a` - The multiplier constant for the LCG.
        /// * `c` - The increment constant for the LCG.
        /// * `m` - The modulus constant for the LCG.
        ///
        /// # Returns
        ///
        /// A new `LCG` instance with the specified seed and constants.
        pub fn init(seed: u128, a: u128, c: u128, m: u128) -> LCG {
            LCG { seed, a, c, m }
        }

        /// Generates the next random number in the sequence.
        ///
        /// # Returns
        ///
        /// The next pseudo-random number in the sequence as a `f64` value between 0 and 1.
        pub fn random(&mut self) -> f64 {
            self.seed = (self.a * self.seed + self.c) % self.m;
            self.seed as f64 / self.m as f64
        }
        pub fn random_f32(&mut self) -> f32 {
            self.seed = (self.a * self.seed + self.c) % self.m;
            self.seed as f32 / self.m as f32
        }
    }
}