Added node.random implementation (#1665)
This commit is contained in:
parent
7c9fdef77a
commit
543f438b6b
|
@ -467,6 +467,79 @@ static int node_osprint( lua_State* L )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int node_random_range(int l, int u) {
|
||||||
|
// The range is the number of different values to return
|
||||||
|
unsigned int range = u + 1 - l;
|
||||||
|
|
||||||
|
// If this is very large then use simpler code
|
||||||
|
if (range >= 0x7fffffff) {
|
||||||
|
unsigned int v;
|
||||||
|
|
||||||
|
// This cannot loop more than half the time
|
||||||
|
while ((v = os_random()) >= range) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now v is in the range [0, range)
|
||||||
|
return v + l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Easy case, with only one value, we know the result
|
||||||
|
if (range == 1) {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another easy case -- uniform 32-bit
|
||||||
|
if (range == 0) {
|
||||||
|
return os_random();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we have to figure out what a large multiple of range is
|
||||||
|
// that just fits into 32 bits.
|
||||||
|
// The limit will be less than 1 << 32 by some amount (not much)
|
||||||
|
uint32_t limit = ((0x80000000 / ((range + 1) >> 1)) - 1) * range;
|
||||||
|
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
while ((v = os_random()) >= limit) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now v is uniformly distributed in [0, limit) and limit is a multiple of range
|
||||||
|
|
||||||
|
return (v % range) + l;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int node_random (lua_State *L) {
|
||||||
|
int u;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
switch (lua_gettop(L)) { /* check number of arguments */
|
||||||
|
case 0: { /* no arguments */
|
||||||
|
#ifdef LUA_NUMBER_INTEGRAL
|
||||||
|
lua_pushnumber(L, 0); /* Number between 0 and 1 - always 0 with ints */
|
||||||
|
#else
|
||||||
|
lua_pushnumber(L, (lua_Number)os_random() / (lua_Number)(1LL << 32));
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case 1: { /* only upper limit */
|
||||||
|
l = 1;
|
||||||
|
u = luaL_checkint(L, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: { /* lower and upper limits */
|
||||||
|
l = luaL_checkint(L, 1);
|
||||||
|
u = luaL_checkint(L, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return luaL_error(L, "wrong number of arguments");
|
||||||
|
}
|
||||||
|
luaL_argcheck(L, l<=u, 2, "interval is empty");
|
||||||
|
lua_pushnumber(L, node_random_range(l, u)); /* int between `l' and `u' */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Module function map
|
// Module function map
|
||||||
|
|
||||||
static const LUA_REG_TYPE node_egc_map[] = {
|
static const LUA_REG_TYPE node_egc_map[] = {
|
||||||
|
@ -504,6 +577,7 @@ static const LUA_REG_TYPE node_map[] =
|
||||||
{ LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) },
|
{ LSTRKEY( "setcpufreq" ), LFUNCVAL( node_setcpufreq) },
|
||||||
{ LSTRKEY( "bootreason" ), LFUNCVAL( node_bootreason) },
|
{ LSTRKEY( "bootreason" ), LFUNCVAL( node_bootreason) },
|
||||||
{ LSTRKEY( "restore" ), LFUNCVAL( node_restore) },
|
{ LSTRKEY( "restore" ), LFUNCVAL( node_restore) },
|
||||||
|
{ LSTRKEY( "random" ), LFUNCVAL( node_random) },
|
||||||
#ifdef LUA_OPTIMIZE_DEBUG
|
#ifdef LUA_OPTIMIZE_DEBUG
|
||||||
{ LSTRKEY( "stripdebug" ), LFUNCVAL( node_stripdebug ) },
|
{ LSTRKEY( "stripdebug" ), LFUNCVAL( node_stripdebug ) },
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -364,6 +364,33 @@ Nothing
|
||||||
node.osprint(true)
|
node.osprint(true)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## node.random()
|
||||||
|
|
||||||
|
This behaves like math.random except that it uses true random numbers derived from the ESP8266 hardware. It returns uniformly distributed
|
||||||
|
numbers in the required range. It also takes care to get large ranges correct.
|
||||||
|
|
||||||
|
It can be called in three ways. Without arguments in the floating point build of NodeMCU, it returns a random real number with uniform distribution in the interval [0,1).
|
||||||
|
When called with only one argument, an integer n, it returns an integer random number x such that 1 <= x <= n. For instance, you can simulate the result of a die with random(6).
|
||||||
|
Finally, random can be called with two integer arguments, l and u, to get a pseudo-random integer x such that l <= x <= u.
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
`node.random()`
|
||||||
|
`node.random(n)`
|
||||||
|
`node.random(l, u)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
- `n` the number of distinct integer values that can be returned -- in the (inclusive) range 1 .. `n`
|
||||||
|
- `l` the lower bound of the range
|
||||||
|
- `u` the upper bound of the range
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
The random number in the appropriate range. Note that the zero argument form will always return 0 in the integer build.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
```lua
|
||||||
|
print ("I rolled a", node.random(6))
|
||||||
|
```
|
||||||
|
|
||||||
# node.egc module
|
# node.egc module
|
||||||
|
|
||||||
## node.egc.setmode()
|
## node.egc.setmode()
|
||||||
|
|
Loading…
Reference in New Issue