Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions random/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ Note that, even if the fast source is implemented using the same
algorithm as the reproducible source (i.e., PGC with a 32-bit state),
the fast source will *not* alter the state of the reproducible PRNG.

## Convenience functions

In addition to `psnip_random_bytes`, the module provides helpers for common cases:

```c
psnip_uint32_t psnip_random_uint32 (enum PSnipRandomSource source);
int psnip_random_int_range(enum PSnipRandomSource source, int min, int max);
double psnip_random_double (enum PSnipRandomSource source);
```

`psnip_random_int_range` returns a value in the inclusive `[min, max]` interval (swapping bounds when `min > max`). `psnip_random_double` returns a value in `[0, 1)`.

## Dependencies

This module requires the following portable-snippet modules:
Expand Down
32 changes: 32 additions & 0 deletions random/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,3 +398,35 @@ psnip_random_bytes(enum PSnipRandomSource source,

return -2;
}

psnip_uint32_t
psnip_random_uint32(enum PSnipRandomSource source) {
psnip_uint32_t value = 0;
if (psnip_random_bytes(source, sizeof(value), (psnip_uint8_t*) &value) != 0)
return 0;
return value;
}

int
psnip_random_int_range(enum PSnipRandomSource source, int min, int max) {
psnip_uint32_t span;
psnip_uint32_t offset;

if (min > max) {
const int tmp = min;
min = max;
max = tmp;
}

if (min == max)
return min;

span = (psnip_uint32_t) ((max - min) + 1);
offset = psnip_random_uint32(source) % span;
return min + (int) offset;
}

double
psnip_random_double(enum PSnipRandomSource source) {
return psnip_random_uint32(source) * (1.0 / 4294967296.0);
}
3 changes: 3 additions & 0 deletions random/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ enum PSnipRandomSource {
int psnip_random_bytes (enum PSnipRandomSource source,
size_t length,
psnip_uint8_t data[PSNIP_RANDOM_ARRAY_PARAM(length)]);
psnip_uint32_t psnip_random_uint32 (enum PSnipRandomSource source);
int psnip_random_int_range(enum PSnipRandomSource source, int min, int max);
double psnip_random_double (enum PSnipRandomSource source);
psnip_uint32_t psnip_random_get_seed (void);
void psnip_random_set_seed (psnip_uint32_t seed);

Expand Down
22 changes: 22 additions & 0 deletions tests/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,32 @@ test_random_fast(const MunitParameter params[], void* data) {
return MUNIT_OK;
}

static MunitResult
test_random_convenience(const MunitParameter params[], void* data) {
int i;

(void) params;
(void) data;

psnip_random_set_seed(1729);

for (i = 0; i < 100; ++i) {
const int value = psnip_random_int_range(PSNIP_RANDOM_SOURCE_REPRODUCIBLE, 3, 7);
munit_assert_int(value, >=, 3);
munit_assert_int(value, <=, 7);
}

munit_assert_double(psnip_random_double(PSNIP_RANDOM_SOURCE_REPRODUCIBLE), >=, 0.0);
munit_assert_double(psnip_random_double(PSNIP_RANDOM_SOURCE_REPRODUCIBLE), <, 1.0);

return MUNIT_OK;
}

static MunitTest test_suite_tests[] = {
{ (char*) "/random/secure", test_random_secure, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/random/reproducible", test_random_reproducible, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/random/fast", test_random_fast, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ (char*) "/random/convenience", test_random_convenience, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
};

Expand Down