Skip to main content

luaur_vm/functions/
math_random.rs

1//! Node: `cxx:Function:Luau.VM:VM/src/lmathlib.cpp:234:math_random`
2//!
3//! `math.random` — 0 args: a double in [0,1) from two PCG32 draws via `ldexp`
4//! (here `* 2^-64`); 1 arg `u`: integer in [1,u]; 2 args `l,u`: integer in
5//! [l,u]. Bounds use the high 32 bits of a 64-bit multiply (Lemire-style) to
6//! avoid modulo bias. Argument checks mirror the C++ exactly.
7
8use crate::functions::lua_gettop::lua_gettop;
9use crate::functions::lua_l_checkinteger::lua_l_checkinteger;
10use crate::functions::lua_pushinteger::lua_pushinteger;
11use crate::functions::lua_pushnumber::lua_pushnumber;
12use crate::functions::pcg_32_random::pcg_32_random;
13use crate::macros::lua_l_argcheck::luaL_argcheck;
14use crate::macros::lua_l_error::luaL_error;
15use crate::type_aliases::lua_state::lua_State;
16
17pub unsafe fn math_random(L: *mut lua_State) -> i32 {
18    let g = (*L).global;
19    match lua_gettop(L) {
20        0 => {
21            let rl = pcg_32_random(&mut (*g).rngstate);
22            let rh = pcg_32_random(&mut (*g).rngstate);
23            let bits = (rl as u64) | ((rh as u64) << 32);
24            let rd = (bits as f64) * 2.0f64.powi(-64);
25            lua_pushnumber(L, rd);
26        }
27        1 => {
28            let u = lua_l_checkinteger(L, 1);
29            luaL_argcheck!(L, 1 <= u, 1, "interval is empty");
30
31            let x = (u as u64).wrapping_mul(pcg_32_random(&mut (*g).rngstate) as u64);
32            let r = (1 + (x >> 32)) as i32;
33            lua_pushinteger(L, r);
34        }
35        2 => {
36            let l = lua_l_checkinteger(L, 1);
37            let u = lua_l_checkinteger(L, 2);
38            luaL_argcheck!(L, l <= u, 2, "interval is empty");
39
40            let ul = (u as u32).wrapping_sub(l as u32);
41            luaL_argcheck!(L, ul < u32::MAX, 2, "interval is too large");
42            let x = (ul as u64 + 1).wrapping_mul(pcg_32_random(&mut (*g).rngstate) as u64);
43            let r = (l as i64 + (x >> 32) as i64) as i32;
44            lua_pushinteger(L, r);
45        }
46        _ => {
47            luaL_error!(L, "wrong number of arguments");
48        }
49    }
50    1
51}