Published .
#include "pcg64.h" // This implementation is by Jonas Hvid, 2025, based in part on the original C++ // and C implementations by Melissa O'Neill, 2019. The latter are each released // under the Apache License, Version 2.0 or the MIT license. To the extent // possible, I dedicate the following code to the public domain. For more // information about copyright, see https://www.pcg-random.org/download.html. // For compilation instructions, see header file. #include <stdint.h> #include <stdlib.h> #include <sys/random.h> static void pcg64_step(pcg64_t *g) { uint128_t m = ((uint128_t)0x2360ED051FC65DA4 << 64) + 0x4385DF649FCCF645; g->s = g->s * m + g->q; } pcg64_t pcg64_init_values(uint128_t state, uint128_t seq) { pcg64_t g; g.s = 0; g.q = (seq << 1u) | 1u; pcg64_step(&g); g.s += state; pcg64_step(&g); return g; } pcg64_t pcg64_init_getrandom() { pcg64_t g; if (getrandom(&g.s, sizeof(uint128_t), 0) != sizeof(uint128_t)) exit(1); if (getrandom(&g.q, sizeof(uint128_t), 0) != sizeof(uint128_t)) exit(1); return pcg64_init_values(g.s, g.q); } static uint64_t pcg64_output(uint128_t s) { // PCG-DXSM uint64_t h = s >> 64; uint64_t l = s; l |= 1; h ^= h >> 32; h *= 0xDA942042E4DD58B5ull; h ^= h >> 48; h *= l; return h; } uint64_t pcg64_random(pcg64_t *g) { pcg64_step(g); return pcg64_output(g->s); } uint64_t pcg64_bounded(pcg64_t *g, uint64_t n) { uint64_t threshold = -n % n; while (1) { uint64_t r = pcg64_random(g); if (r >= threshold) { return r % n; } } }
#ifndef PCG64_H #define PCG64_H // Build and use shared library: // gcc -std=c23 -c -fpic -o pcg64.o pcg64.c // gcc -shared -o libpcg64.so pcg64.o // gcc -lpcg64 -o main main.c // // Link statically: // gcc -std=c23 -c -o pcg64.o pcg64.c // gcc -o main main.c pcg64.o // This implementation depends on native support for __int128. // For copyright, see implementation file. #include <stdint.h> typedef unsigned __int128 uint128_t; typedef struct pcg64_t { uint128_t s; uint128_t q; } pcg64_t; pcg64_t pcg64_init_values(uint128_t state, uint128_t seq); pcg64_t pcg64_init_getrandom(); uint64_t pcg64_random(pcg64_t *); uint64_t pcg64_bounded(pcg64_t *, uint64_t n); #endif
#include <stdio.h> #include "pcg64.h" int main() { pcg64_t state = pcg64_init_getrandom(); for (int i = 0; i < 16; ++i) { printf("%02lX ", pcg64_bounded(&state, 0x100)); } printf("\n"); return 0; }
CF = -std=c23 -Wall -Wextra -Os LF = -s C = gcc demo-static: demo.c pcg64.c $(C) $(CF) $(LF) -o $@ $^ demo-dynamic: demo.c libpcg64.so $(C) $(CF) $(LF) -L. -lpcg64 -Wl,-rpath,'$$ORIGIN' -o $@ $< libpcg64.so: pcg64.c $(C) $(CF) $(LF) -fpic -shared -o $@ $< .PHONY: clean clean: rm -fv *.o *.so demo-{static,dynamic}