Skip to main content

ganit_core/eval/functions/math/randarray/
mod.rs

1use crate::eval::coercion::to_number;
2use crate::eval::functions::check_arity;
3use crate::types::{ErrorKind, Value};
4
5fn random_number() -> f64 {
6    let seed = std::time::SystemTime::now()
7        .duration_since(std::time::UNIX_EPOCH)
8        .map(|d| d.subsec_nanos())
9        .unwrap_or(12345);
10    let val = seed.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
11    (val as f64) / (u32::MAX as f64 + 1.0)
12}
13
14/// `RANDARRAY([rows], [cols], [min], [max], [integer])`
15///
16/// Returns an array of random numbers.
17/// With no args: returns a single random number (equivalent to RAND()).
18/// With rows/cols: returns a nested 2D array (rows × cols).
19pub fn randarray_fn(args: &[Value]) -> Value {
20    if args.is_empty() {
21        // No args: return single random number
22        return Value::Number(random_number());
23    }
24    if let Some(err) = check_arity(args, 1, 5) {
25        return err;
26    }
27    let rows = match to_number(args[0].clone()) {
28        Err(e) => return e,
29        Ok(v) => v,
30    };
31    if rows <= 0.0 {
32        return Value::Error(ErrorKind::Num);
33    }
34    let rows = rows as usize;
35    let cols = if args.len() >= 2 {
36        match to_number(args[1].clone()) {
37            Err(e) => return e,
38            Ok(v) => {
39                if v <= 0.0 {
40                    return Value::Error(ErrorKind::Num);
41                }
42                v as usize
43            }
44        }
45    } else {
46        1
47    };
48
49    // Always return nested 2D array so ROWS/COLUMNS work correctly
50    let outer: Vec<Value> = (0..rows)
51        .map(|_| {
52            let row: Vec<Value> = (0..cols).map(|_| Value::Number(random_number())).collect();
53            Value::Array(row)
54        })
55        .collect();
56    Value::Array(outer)
57}