Banjo API 1.0.0-rc.2
Low-level C99 game development API
Loading...
Searching...
No Matches
random.c
Go to the documentation of this file.
1
16
17#include <banjo/log.h>
18#include <banjo/main.h>
19#include <banjo/random.h>
20#include <banjo/time.h>
21#include <string.h>
22
23// Helper: build a 64-bit value by combining two 32-bit draws.
24// PCG32 generates 32-bit values, but you can combine them for larger ranges.
25static uint64_t pcg32_u64(bj_pcg32 *g) {
26 uint64_t hi = (uint64_t)bj_next_pcg32(g);
27 uint64_t lo = (uint64_t)bj_next_pcg32(g);
28 return (hi << 32) | lo;
29}
30
31int main(int argc, char* argv[]) {
32 (void)argc; (void)argv;
33
34 // Global API: bj_rand() works like C stdlib rand(). It uses hidden global
35 // state, so it's simple but not suitable when you need independent streams.
36 bj_info("Before srand():");
37 for (size_t i = 0; i < 5; ++i) {
38 bj_info("\tbj_rand() -> %d", bj_rand());
39 }
40
41 // Seed the global generator. Use current time for non-deterministic results.
42 bj_srand((unsigned)bj_get_time());
43 bj_info("After srand():");
44 for (size_t i = 0; i < 5; ++i) {
45 bj_info("\tbj_rand() -> %d", bj_rand());
46 }
47
48 // PCG32 API: Each bj_pcg32 is an independent generator with its own state.
49 // This allows multiple random streams that don't interfere with each other.
50 bj_info("PCG32:");
51
52 // Zero-initialised generators have a default seed. They produce the same
53 // sequence every run, which is useful for reproducible testing.
54 bj_pcg32 g0 = (bj_pcg32){0};
55 bj_info("\tzero-init stream:");
56 for (size_t i = 0; i < 3; ++i) {
57 bj_info("\t\t%10u", bj_next_pcg32(&g0));
58 }
59
60 // Seed with current time for non-deterministic results. The sequence
61 // parameter (54) selects which stream to use. Same seed + different sequence
62 // = independent random numbers.
63 bj_pcg32 g1 = (bj_pcg32){0};
64 bj_seed_pcg32(&g1, (uint64_t)bj_get_time(), 54u);
65 bj_info("\tseeded with time, seq=54:");
66 for (size_t i = 0; i < 3; ++i) {
67 bj_info("\t\t%10u", bj_next_pcg32(&g1));
68 }
69
70 // Different sequence number creates an independent stream. Even with the
71 // same seed, seq=55 produces completely different numbers than seq=54.
72 // This is useful for having separate random streams per game entity.
73 bj_pcg32 g2 = (bj_pcg32){0};
74 bj_seed_pcg32(&g2, (uint64_t)bj_get_time(), 55u);
75 bj_info("\tseeded with time, seq=55 (independent):");
76 for (size_t i = 0; i < 3; ++i) {
77 bj_info("\t\t%10u", bj_next_pcg32(&g2));
78 }
79
80 // Query the range of values PCG32 can generate (0 to UINT32_MAX).
81 bj_info("\tmin=%u max=%u", bj_min_pcg32(), bj_max_pcg32());
82
83 // Jump-ahead: bj_discard_pcg32() efficiently skips values without generating
84 // them. This is useful for synchronizing streams or implementing parallel
85 // random number generation.
86 bj_pcg32 gA = (bj_pcg32){0};
87 bj_pcg32 gB = (bj_pcg32){0};
88 bj_seed_pcg32(&gA, 1234u, 999u);
89 bj_seed_pcg32(&gB, 1234u, 999u);
90 for (size_t i = 0; i < 10; ++i) (void)bj_next_pcg32(&gA); // Manually advance gA
91 bj_discard_pcg32(&gB, 10); // Efficiently skip 10 values in gB
92 bj_info("\tdiscard(10) aligns streams: %u vs %u", bj_next_pcg32(&gA), bj_next_pcg32(&gB));
93
94 // Building larger values: combine multiple 32-bit draws for wider ranges.
95 // This is how you'd generate uint64_t random numbers.
96 bj_pcg32 g64 = (bj_pcg32){0};
97 bj_seed_pcg32(&g64, 0xCAFEBABEULL, 0xDEADULL);
98 uint64_t x = pcg32_u64(&g64);
99 bj_info("\tu64 from two draws: 0x%016llx", (unsigned long long)x);
100
101 return 0;
102}
int main(int argc, char *argv[])
Definition audio_pcm.c:177
#define bj_info(...)
Log a message using the BJ_LOG_INFO level.
Definition log.h:141
void bj_seed_pcg32(struct bj_pcg32 *generator, uint64_t seed, uint64_t seq)
Set the generator state from seed and sequence.
uint32_t bj_min_pcg32(void)
Smallest possible value returned by the generator.
void bj_discard_pcg32(struct bj_pcg32 *generator, uint64_t z)
Advance the generator state by z steps.
uint32_t bj_max_pcg32(void)
Largest possible value returned by the generator.
void bj_srand(unsigned int seed)
Seed the standard PRNG.
int bj_rand(void)
Generate a pseudo-random integer in [0, BJ_RAND_MAX].
uint32_t bj_next_pcg32(struct bj_pcg32 *generator)
Advance the generator and return the next 32-bit value.
PCG32 generator state.
Definition random.h:114
uint64_t bj_get_time(void)
Get the current system time in seconds since the Unix epoch.
Logging utility functions.
Portable main() replacement with platform-aware entry shim.
static uint64_t pcg32_u64(bj_pcg32 *g)
Definition random.c:25
Pseudo-random number generation API.
String utility functions.
Header file for time manipulation utilities.