Regression: Invalid is_random implementation due to changes in 0.6.

This commit is contained in:
Christoffer Lerno
2024-07-26 20:18:55 +02:00
parent 34993a20fd
commit e1565ccdc5
3 changed files with 82 additions and 14 deletions

View File

@@ -1,18 +1,15 @@
/**
* Randoms:
* General usage -
* 1. Create a Random (see std/math/random for various alternatives), or pick DefaultRandom
* 2. Define it `DefaultRandom my_random;`
* 3. Seed it: `random::seed(&my_random, some_seed);` or `rand::seed_entropy(&my_random);`
* 4. Use it with the functions in random: `float random_float = random::next_float(&my_random);`
*
* For just a simple integer between 0 and n (not including n), you can use `rand(n)`.
**/
module std::math::random;
interface Random
{
fn void set_seed(char[] input);
fn char next_byte();
fn ushort next_short();
fn uint next_int();
fn ulong next_long();
fn uint128 next_int128();
fn void next_bytes(char[] buffer);
}
macro bool is_random(random) => $assignable(random, Random*);
/**
* @require is_random(random)
**/
@@ -21,12 +18,19 @@ macro void seed(random, seed)
random.set_seed(@as_char_view(seed));
}
/**
* Seed the random with some best effort entropy.
*
* @require is_random(random)
**/
macro void seed_entropy(random)
{
random.set_seed(&&entropy());
}
/**
* Get the next value between 0 and max (not including max).
*
* @require is_random(random)
**/
macro int next(random, int max)
@@ -34,6 +38,11 @@ macro int next(random, int max)
return (int)(next_double(random) * max);
}
def DefaultRandom = Sfc64Random;
/**
* Get a default random value between 0 and max (not including max)
**/
fn int rand(int max) @builtin
{
tlocal Sfc64Random default_random;
@@ -45,15 +54,20 @@ fn int rand(int max) @builtin
}
return next(&default_random, max);
}
/**
* Get 'true' or 'false'
*
* @require is_random(random)
**/
macro bool next_bool(random)
{
return random.next_byte() & 1;
return (bool)(random.next_byte() & 1);
}
/**
* Get a float between 0 and 1.0, not including 1.0.
*
* @require is_random(random)
**/
macro float next_float(random)
@@ -63,6 +77,8 @@ macro float next_float(random)
}
/**
* Get a double between 0 and 1.0, not including 1.0.
*
* @require is_random(random)
**/
macro double next_double(random)
@@ -71,6 +87,9 @@ macro double next_double(random)
return val * 0x1.0p-53;
}
// True if the value is a Random.
macro bool is_random(random) => $assignable(random, Random);
macro uint128 @long_to_int128(#function) => (uint128)#function << 64 + #function;
macro ulong @int_to_long(#function) => (ulong)#function << 32 + #function;
macro uint @short_to_int(#function) => (uint)#function << 16 + #function;
@@ -95,3 +114,16 @@ macro @random_value_to_bytes(#function, char[] bytes)
}
unreachable();
}
// This is the interface to implement for Random implementations, usually
// it is not invoked directly.
interface Random
{
fn void set_seed(char[] input);
fn char next_byte();
fn ushort next_short();
fn uint next_int();
fn ulong next_long();
fn uint128 next_int128();
fn void next_bytes(char[] buffer);
}

View File

@@ -13,6 +13,7 @@
### Fixes
- Broken WASM library code.
- Regression: Invalid is_random implementation due to changes in 0.6.
### Stdlib changes
None

View File

@@ -0,0 +1,35 @@
module std::math::random @test;
import std::math;
fn void test_regular_random()
{
for (int i = 0; i < 100; i++) assert(rand(45) < 45 && rand(45) >= 0);
}
fn void test_next_bool()
{
DefaultRandom rand;
random::seed_entropy(&rand);
for (int i = 0; i < 100; i++) random::next_bool(&rand);
}
fn void test_next()
{
DefaultRandom rand;
random::seed_entropy(&rand);
for (int i = 0; i < 100; i++) assert(random::next(&rand, 100) < 100.0 && random::next(&rand, 100) >= 0);
}
fn void test_next_double()
{
DefaultRandom rand;
random::seed_entropy(&rand);
for (int i = 0; i < 100; i++) assert(random::next_double(&rand) < 1.0 && random::next_double(&rand) >= 0);
}
fn void test_next_float()
{
DefaultRandom rand;
random::seed_entropy(&rand);
for (int i = 0; i < 100; i++) assert(random::next_float(&rand) < 1.0 && random::next_float(&rand) >= 0);
}