mathlab/functions/args/
mod.rs

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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
use super::num::{fix, fix64};

/// ### monolist(x, size)
///
/// Generating function
///
/// The `monolist` function generates a list of specified length containing only a given float value `x`.
/// The maximum allowed length is limited to 1 million to prevent excessive resource consumption.
///
/// ### Examples
/// ```rust
/// use mathlab::math::{monolist, fix64};
/// assert_eq!(monolist(0.1, 0), []);
/// assert_eq!(monolist(0.1, 1000000000), monolist(0.1, 1000000000)); // if size > 1 million {  function will replace size with 0 } -> []
/// assert_eq!(monolist(-1.0, 2), [-1.0, -1.0]);
/// assert_eq!(monolist(0.0, 2), [0.0, 0.0]);
/// assert_eq!(monolist(1.0, 2), [1.0, 1.0]);
/// assert_eq!(monolist(0.1 + 0.2, 2), [0.3, 0.3]);
/// assert_eq!(monolist(0.30000000000000004, 2), [0.3, 0.3]);
/// ```
/// <small>End Fun Doc</small>
pub fn monolist(x: f64, mut size: usize) -> Vec<f64> {
    if size > 1_000_000 {
        size = 0
    }
    let mut vector = Vec::with_capacity(size);
    for _i in 0..size {
        vector.push(fix64(x))
    }
    vector
}

/// ### range(x, step, size, order)
///
/// Generating function
///
/// The `range` function generates a list of up to one million elements representing a sequence of float numbers
/// spaced by the provided step value starting at x, optionally sorted either ascending ("asc") or descending ("desc").
/// Returns an empty vector if size exceeds one million, or if step is nonpositive.
///
/// ### Examples
/// ```rust
/// use mathlab::math::range;
/// // For the order argument, use "asc" for ascending order or "desc" for descending order, otherwise the function will return [].
/// assert_eq!(range(0.0, 0.1, 10, "abcd"), []);
/// assert_eq!(range(0.0, 0.1, 0, "asc"), []); // The parameter size must be from 1 to 1 million.
/// assert_eq!(range(0.0, 0.1, 1000000000, "asc"), []); // The parameter size must be from 1 to 1 million.
/// assert_eq!(range(1.0, 1.0, 10, "asc"), [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]);
/// assert_eq!(range(0.0, 0.1, 10, "asc"), [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]);
/// assert_eq!(range(0.0, 0.1, 10, "desc"), [0.0, -0.1, -0.2, -0.3, -0.4, -0.5, -0.6, -0.7, -0.8, -0.9]);
/// assert_eq!(range(0.9, 0.1, 10, "desc"), [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]);
/// assert_eq!(range(0.0, 2.0, 3, "asc"), [0.0, 2.0, 4.0]);
/// assert_eq!(range(4.0, 2.0, 3, "desc"), [4.0, 2.0, 0.0]);
/// ```
/// <small>End Fun Doc</small>
pub fn range(x: f64, step: f64, mut size: usize, order: &str) -> Vec<f64> {
    if size > 1_000_000 || step <= 0.0 {
        size = 0
    }
    let mut vector = Vec::with_capacity(size);
    for _i in 0..size {
        if order == "asc" {
            vector.push(fix64(x + (_i as f64 * step)))
        } else if order == "desc" {
            vector.push(fix64(x - (_i as f64 * step)))
        } else {
            return vector;
        }
    }
    vector
}

/// ### to_fixed(x, decimal_places)
///
/// Fixation Function
///
/// The `to_fixed` function converts a floating-point number `x` to a string with a specified
/// number of decimal places, returning a fixed-point string representation.
///
/// ### Examples
/// ```rust
/// use mathlab::math::{to_fixed, fix, is_nan_f64, INF_F64 as inf, NAN_F64 as NaN};
/// assert_eq!(to_fixed(0.5235987755982988, 3), "0.524");
/// assert_eq!(to_fixed(0.5235987755982928, 15), "0.523598775598293");
/// assert_eq!(to_fixed(0.5235987755982928, 1), "0.5");
/// assert_eq!(to_fixed(0.5235987755982928, 0), "1");
/// assert_eq!(to_fixed(0.0, 0), "0");
/// assert_eq!(to_fixed(inf, 0), "inf");
/// assert_eq!(to_fixed(inf, 0), "inf");
/// assert_eq!(to_fixed(NaN, 0), "NaN");
/// assert!(is_nan_f64(fix(NaN, 0)));
/// assert_eq!(to_fixed(0.1 + 0.2, 15), "0.3");
/// ```
/// <small>End Fun Doc</small>
pub fn to_fixed(x: f64, decimal_places: u32) -> String {
    fix(x, decimal_places).to_string()
}

/// ### hypot(x)
///
/// Geometric Function
///
/// The `hypot` function calculates the Euclidean norm (also known as the magnitude or length) of a vector in n-dimensional space.
///
/// ### Examples
/// ```rust
/// use mathlab::math::{hypot, INF_F64 as inf, is_nan_f64 as is_nan};
/// assert_eq!(hypot(&[0.0]), 0.0);
/// assert_eq!(hypot(&[1.0]), 1.0);
/// assert_eq!(hypot(&[1.0 / 0.0]), inf);
/// assert!(is_nan(hypot(&[0.0 / 0.0])));
/// assert_eq!(hypot(&[4.0]), 4.0);
/// assert_eq!(hypot(&[3.0, 4.0]), 5.0);
/// assert_eq!(hypot(&[4.0, 2.0, 4.0]), 6.0);
/// assert_eq!(hypot(&[-3.0, -4.0]), 5.0);
/// assert_eq!(hypot(&[-4.0]), 4.0);
/// ```
/// <small>End Fun Doc</small>
pub fn hypot(x: &[f64]) -> f64 {
    if x.len() > 0 && x.iter().all(|i| i as *const f64 != std::ptr::null()) {
        x.iter().map(|i| i.powi(2)).sum::<f64>().sqrt()
    } else {
        std::f64::NAN
    }
}

/////////////////// RAND FUNCTION ///////////////////

use std::time::{Duration, SystemTime, UNIX_EPOCH};

/// Returns the current UTC time as a `SystemTime`.
///
/// This function uses the standard library function to get the current time.
fn utc_now() -> SystemTime {
    SystemTime::now()
}

/// Returns the duration since the UNIX epoch (January 1, 1970).
///
/// This function retrieves the current time and calculates how long it has been since
/// the UNIX epoch, returning it as a `Duration`.
fn duration_since() -> Duration {
    utc_now()
        .duration_since(UNIX_EPOCH)
        .expect("Time went backwards")
}

/// Returns the current time in nanoseconds (within the last second).
///
/// The result is the remainder of the nanoseconds since the epoch, modulo 1,000,000,
/// effectively returning nanoseconds as a value between 0 and 999,999.
fn get_nanos() -> u64 {
    let nanos = duration_since().as_nanos() % 1_000_000;
    nanos as u64
}

/// Returns the current time in milliseconds (within the last second).
///
/// The result is the remainder of the milliseconds since the epoch, modulo 1,000,
/// effectively returning milliseconds as a value between 0 and 999.
fn get_millis() -> u64 {
    let millis = duration_since().as_millis() % 1000;
    millis as u64
}

/// Returns the current second (within the last minute).
///
/// This function retrieves the current seconds since the UNIX epoch
/// and returns it as a value between 0 and 59.
fn get_second() -> u64 {
    let second = duration_since().as_secs() % 60;
    second
}

/// ### string_to_u64(s)
///
/// Converts a string into a `u64`.
///
/// This function attempts to parse the provided string `s` into a `u64`.
/// If successful, it returns `Ok(u64)`, otherwise an error of type `ParseIntError`.
///
/// ### Examples
/// ```
/// use mathlab::math::string_to_u64;
///
/// let result = string_to_u64("12345".to_string());
/// assert_eq!(result, Ok(12345));
/// ```
/// <small>End Fun Doc</small>
pub fn string_to_u64(s: String) -> Result<u64, std::num::ParseIntError> {
    s.parse::<u64>()
}

/// Formats a `u64` number to ensure it is a 10-digit representation.
///
/// If the number has more than 10 digits, it truncates the leftmost digits.
/// If it has fewer than 10 digits, it pads the number with leading zeros
/// to ensure it has exactly 10 digits. format_number_10d(123) ==> 0000000123
fn format_number_10d(num: u64) -> u64 {
    let number_str = num.to_string();
    let length = number_str.len();
    if length > 10 {
        let truncated_str = &number_str[length - 10..];
        return truncated_str.parse::<u64>().unwrap();
    } else {
        let padded_str = format!("{}{:0>10}", &number_str, "0".repeat(10 - length));
        return padded_str[..10].parse::<u64>().unwrap();
    }
}

/// Generates a formatted string combining nanos, millis, and seconds.
///
/// This function creates a string representation of the current time using nanoseconds,
/// milliseconds, and seconds, then formats it as a `u64` ensuring it is 10 digits.
pub fn formatted() -> String {
    let num = format!("{:?}{:?}{:?}", get_nanos(), get_millis(), get_second());
    format!("{}", format_number_10d(string_to_u64(num).expect("REASON")))
}

/// ### rand(size)
///
/// Generates a pseudo-random `u64` number within the specified digit size.
///
/// The `size` parameter determines the number of digits for the generated random number.
/// The function will cap the `size` at 19 if requested larger to ensure it fits within the
/// limits of `u64`, preventing overflow.
///
/// ### Parameters
/// - `size`: The desired number of digits for the random number. Must be greater than 0.
///
/// ### Returns
/// A `u64` random number with digit count as specified, capped at 19.
///
/// ### Examples
/// ```rust
/// use mathlab::math::rand;
///
/// fn main() {
///    // Generating and printing random numbers of different sizes
///    println!("Random number (size 1): {:?}", rand(1));
///    println!("Random number (size 2): {:?}", rand(2));
///    println!("Random number (size 3): {:?}", rand(3));
///    println!("Random number (size 6): {:?}", rand(6));
///    println!("Random number (size 15): {:?}", rand(15));
///    println!("Random number (size 19): {:?}", rand(19));
///    println!("Random number (size 19, requested 25): {:?}", rand(25)); // Size capped at 19
/// }
/// ```
/// <small>End Fun Doc</small>
pub fn rand(mut size: usize) -> u64 {
    if size == 0 {
        return 0; // Handle size 0 case
    }

    if size > 19 {
        size = 19; // Cap max size to 19 digits
    }

    // Calculate the minimum and maximum ranges
    let min = 10u64.pow((size - 1) as u32); // 10^(size - 1)
    let max = 10u64.pow(size as u32) - 1; // 10^size - 1

    // Generate a seed using system time
    let nanos = get_nanos();
    let millis = get_millis();
    let seconds = get_second();

    // Create a complex random seed using sine and different time-derived components
    let time_combined = (nanos as f64) + ((millis as f64) * 1e-3) + ((seconds as f64) * 1e-6);

    // Use sine function to create some variability
    let sine_value = (time_combined * std::f64::consts::PI * 0.1).sin() * 1e19; // Scale to 19-digit range

    // Combine the sine value into the final random seed
    let random_seed = (sine_value.abs() as u64) % (max - min + 1);

    // Calculate the final random number
    let random_number = min + random_seed;

    random_number
}

/////////////////// END RAND FUNCTION ///////////////////