squiggle.c

Self-contained Monte Carlo estimation in C99
Log | Files | Refs | README

commit 9e1d4ee6d4597a1f47b612168e7002b78cb3400a
parent 11286211f7a6c725f60c224c16321234112e9525
Author: NunoSempere <nuno.sempere@protonmail.com>
Date:   Sun, 23 Jul 2023 12:47:47 +0200

move to xorshift64. Better precision.

Diffstat:
MREADME.md | 6+++---
Mexamples/01_one_sample/example | 0
Mexamples/01_one_sample/example.c | 12++++++------
Mexamples/02_many_samples/example | 0
Mexamples/02_many_samples/example.c | 12++++++------
Mexamples/03_gcc_nested_function/example | 0
Mexamples/03_gcc_nested_function/example.c | 12++++++------
Mexamples/04_sample_from_cdf_simple/example | 0
Mexamples/04_sample_from_cdf_simple/example.c | 4++--
Mexamples/05_sample_from_cdf_beta/example | 0
Mexamples/05_sample_from_cdf_beta/example.c | 4++--
Mexamples/06_gamma_beta/example | 0
Mexamples/06_gamma_beta/example.c | 2+-
Msquiggle.c | 34+++++++++++++++++-----------------
Msquiggle.h | 26+++++++++++++-------------
Mtest/test | 0
Mtest/test.c | 8++++----
17 files changed, 60 insertions(+), 60 deletions(-)

diff --git a/README.md b/README.md @@ -128,7 +128,7 @@ In squiggle.c, this ambiguity doesn't exist, at the cost of much greater overhea int main(){ // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with a seed of 0 float a = sample_to(1, 10, seed); @@ -153,7 +153,7 @@ vs #include <stdlib.h> #include <stdio.h> -float draw_xyz(uint32_t* seed){ +float draw_xyz(uint64_t* seed){ // function could also be placed inside main with gcc nested functions extension. return sample_to(1, 20, seed); } @@ -161,7 +161,7 @@ float draw_xyz(uint32_t* seed){ int main(){ // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with a seed of 0 float a = draw_xyz(seed); diff --git a/examples/01_one_sample/example b/examples/01_one_sample/example Binary files differ. diff --git a/examples/01_one_sample/example.c b/examples/01_one_sample/example.c @@ -4,29 +4,29 @@ #include <stdio.h> // Estimate functions -float sample_0(uint32_t* seed) +float sample_0(uint64_t* seed) { return 0; } -float sample_1(uint32_t* seed) +float sample_1(uint64_t* seed) { return 1; } -float sample_few(uint32_t* seed) +float sample_few(uint64_t* seed) { return sample_to(1, 3, seed); } -float sample_many(uint32_t* seed) +float sample_many(uint64_t* seed) { return sample_to(2, 10, seed); } int main(){ // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with 0 float p_a = 0.8; @@ -35,7 +35,7 @@ int main(){ int n_dists = 4; float weights[] = { 1 - p_c, p_c / 2, p_c / 4, p_c / 4 }; - float (*samplers[])(uint32_t*) = { sample_0, sample_1, sample_few, sample_many }; + float (*samplers[])(uint64_t*) = { sample_0, sample_1, sample_few, sample_many }; float result_one = sample_mixture(samplers, weights, n_dists, seed); printf("result_one: %f\n", result_one); diff --git a/examples/02_many_samples/example b/examples/02_many_samples/example Binary files differ. diff --git a/examples/02_many_samples/example.c b/examples/02_many_samples/example.c @@ -4,29 +4,29 @@ #include "../../squiggle.h" // Estimate functions -float sample_0(uint32_t* seed) +float sample_0(uint64_t* seed) { return 0; } -float sample_1(uint32_t* seed) +float sample_1(uint64_t* seed) { return 1; } -float sample_few(uint32_t* seed) +float sample_few(uint64_t* seed) { return sample_to(1, 3, seed); } -float sample_many(uint32_t* seed) +float sample_many(uint64_t* seed) { return sample_to(2, 10, seed); } int main(){ // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with 0 float p_a = 0.8; @@ -35,7 +35,7 @@ int main(){ int n_dists = 4; float weights[] = { 1 - p_c, p_c / 2, p_c / 4, p_c / 4 }; - float (*samplers[])(uint32_t*) = { sample_0, sample_1, sample_few, sample_many }; + float (*samplers[])(uint64_t*) = { sample_0, sample_1, sample_few, sample_many }; int n_samples = 1000000; float* result_many = (float *) malloc(n_samples * sizeof(float)); diff --git a/examples/03_gcc_nested_function/example b/examples/03_gcc_nested_function/example Binary files differ. diff --git a/examples/03_gcc_nested_function/example.c b/examples/03_gcc_nested_function/example.c @@ -5,7 +5,7 @@ int main(){ // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with 0 float p_a = 0.8; @@ -14,12 +14,12 @@ int main(){ int n_dists = 4; - float sample_0(uint32_t* seed){ return 0; } - float sample_1(uint32_t* seed) { return 1; } - float sample_few(uint32_t* seed){ return sample_to(1, 3, seed); } - float sample_many(uint32_t* seed){ return sample_to(2, 10, seed); } + float sample_0(uint64_t* seed){ return 0; } + float sample_1(uint64_t* seed) { return 1; } + float sample_few(uint64_t* seed){ return sample_to(1, 3, seed); } + float sample_many(uint64_t* seed){ return sample_to(2, 10, seed); } - float (*samplers[])(uint32_t*) = { sample_0, sample_1, sample_few, sample_many }; + float (*samplers[])(uint64_t*) = { sample_0, sample_1, sample_few, sample_many }; float weights[] = { 1 - p_c, p_c / 2, p_c / 4, p_c / 4 }; int n_samples = 1000000; diff --git a/examples/04_sample_from_cdf_simple/example b/examples/04_sample_from_cdf_simple/example Binary files differ. diff --git a/examples/04_sample_from_cdf_simple/example.c b/examples/04_sample_from_cdf_simple/example.c @@ -49,7 +49,7 @@ void test_inverse_cdf_float(char* cdf_name, float cdf_float(float)) } } -void test_and_time_sampler_float(char* cdf_name, float cdf_float(float), uint32_t* seed) +void test_and_time_sampler_float(char* cdf_name, float cdf_float(float), uint64_t* seed) { printf("\nGetting some samples from %s:\n", cdf_name); clock_t begin = clock(); @@ -75,7 +75,7 @@ int main() // Testing samplers // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with 0 // Test float sampler diff --git a/examples/05_sample_from_cdf_beta/example b/examples/05_sample_from_cdf_beta/example Binary files differ. diff --git a/examples/05_sample_from_cdf_beta/example.c b/examples/05_sample_from_cdf_beta/example.c @@ -131,7 +131,7 @@ void test_inverse_cdf_box(char* cdf_name, struct box cdf_box(float)) } } -void test_and_time_sampler_box(char* cdf_name, struct box cdf_box(float), uint32_t* seed) +void test_and_time_sampler_box(char* cdf_name, struct box cdf_box(float), uint64_t* seed) { printf("\nGetting some samples from %s:\n", cdf_name); clock_t begin = clock(); @@ -154,7 +154,7 @@ int main() test_inverse_cdf_box("cdf_beta", cdf_beta); // Test box sampler - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with 0 test_and_time_sampler_box("cdf_beta", cdf_beta, seed); // Ok, this is slower than python!! diff --git a/examples/06_gamma_beta/example b/examples/06_gamma_beta/example Binary files differ. diff --git a/examples/06_gamma_beta/example.c b/examples/06_gamma_beta/example.c @@ -8,7 +8,7 @@ int main() { // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with 0 int n = 1000 * 1000; diff --git a/squiggle.c b/squiggle.c @@ -14,14 +14,14 @@ const float PI = 3.14159265358979323846; // M_PI in gcc gnu99 // Pseudo Random number generator -uint32_t xorshift32(uint32_t* seed) +uint64_t xorshift32(uint32_t* seed) { // Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" - // See <https://stackoverflow.com/questions/53886131/how-does-xorshift32-works> + // See <https://stackoverflow.com/questions/53886131/how-does-xorshift64-works> // https://en.wikipedia.org/wiki/Xorshift // Also some drama: <https://www.pcg-random.org/posts/on-vignas-pcg-critique.html>, <https://prng.di.unimi.it/> - uint32_t x = *seed; + uint64_t x = *seed; x ^= x << 13; x ^= x >> 17; x ^= x << 5; @@ -31,7 +31,7 @@ uint32_t xorshift32(uint32_t* seed) uint64_t xorshift64(uint64_t* seed) { // Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" - // See <https://stackoverflow.com/questions/53886131/how-does-xorshift32-works> + // See <https://stackoverflow.com/questions/53886131/how-does-xorshift64-works> // https://en.wikipedia.org/wiki/Xorshift // Also some drama: <https://www.pcg-random.org/posts/on-vignas-pcg-critique.html>, <https://prng.di.unimi.it/> @@ -44,13 +44,13 @@ uint64_t xorshift64(uint64_t* seed) // Distribution & sampling functions // Unit distributions -float sample_unit_uniform(uint32_t* seed) +float sample_unit_uniform(uint64_t* seed) { // samples uniform from [0,1] interval. - return ((float)xorshift32(seed)) / ((float)UINT32_MAX); + return ((float)xorshift64(seed)) / ((float)UINT64_MAX); } -float sample_unit_normal(uint32_t* seed) +float sample_unit_normal(uint64_t* seed) { // See: <https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform> float u1 = sample_unit_uniform(seed); @@ -60,22 +60,22 @@ float sample_unit_normal(uint32_t* seed) } // Composite distributions -float sample_uniform(float start, float end, uint32_t* seed) +float sample_uniform(float start, float end, uint64_t* seed) { return sample_unit_uniform(seed) * (end - start) + start; } -float sample_normal(float mean, float sigma, uint32_t* seed) +float sample_normal(float mean, float sigma, uint64_t* seed) { return (mean + sigma * sample_unit_normal(seed)); } -float sample_lognormal(float logmean, float logsigma, uint32_t* seed) +float sample_lognormal(float logmean, float logsigma, uint64_t* seed) { return expf(sample_normal(logmean, logsigma, seed)); } -float sample_to(float low, float high, uint32_t* seed) +float sample_to(float low, float high, uint64_t* seed) { // Given a (positive) 90% confidence interval, // returns a sample from a lognormal @@ -88,7 +88,7 @@ float sample_to(float low, float high, uint32_t* seed) return sample_lognormal(logmean, logsigma, seed); } -float sample_gamma(float alpha, uint32_t* seed) +float sample_gamma(float alpha, uint64_t* seed) { // A Simple Method for Generating Gamma Variables, Marsaglia and Wan Tsang, 2001 @@ -125,7 +125,7 @@ float sample_gamma(float alpha, uint32_t* seed) } } -float sample_beta(float a, float b, uint32_t* seed) +float sample_beta(float a, float b, uint64_t* seed) { float gamma_a = sample_gamma(a, seed); float gamma_b = sample_gamma(b, seed); @@ -168,7 +168,7 @@ float array_std(float* array, int length) } // Mixture function -float sample_mixture(float (*samplers[])(uint32_t*), float* weights, int n_dists, uint32_t* seed) +float sample_mixture(float (*samplers[])(uint64_t*), float* weights, int n_dists, uint64_t* seed) { // You can see a simpler version of this function in the git history // or in C-02-better-algorithm-one-thread/ @@ -364,13 +364,13 @@ struct box inverse_cdf_box(struct box cdf_box(float), float p) } // Sampler based on inverse cdf and randomness function -struct box sampler_cdf_box(struct box cdf(float), uint32_t* seed) +struct box sampler_cdf_box(struct box cdf(float), uint64_t* seed) { float p = sample_unit_uniform(seed); struct box result = inverse_cdf_box(cdf, p); return result; } -struct box sampler_cdf_float(float cdf(float), uint32_t* seed) +struct box sampler_cdf_float(float cdf(float), uint64_t* seed) { float p = sample_unit_uniform(seed); struct box result = inverse_cdf_float(cdf, p); @@ -378,7 +378,7 @@ struct box sampler_cdf_float(float cdf(float), uint32_t* seed) } /* Could also define other variations, e.g., -float sampler_danger(struct box cdf(float), uint32_t* seed) +float sampler_danger(struct box cdf(float), uint64_t* seed) { float p = sample_unit_uniform(seed); struct box result = inverse_cdf_box(cdf, p); diff --git a/squiggle.h b/squiggle.h @@ -1,24 +1,24 @@ #ifndef SQUIGGLEC #define SQUIGGLEC -// uint32_t header +// uint64_t header #include <stdint.h> // Pseudo Random number generator -uint32_t xorshift32(uint32_t* seed); +uint64_t xorshift64(uint64_t* seed); // Basic distribution sampling functions -float sample_unit_uniform(uint32_t* seed); -float sample_unit_normal(uint32_t* seed); +float sample_unit_uniform(uint64_t* seed); +float sample_unit_normal(uint64_t* seed); // Composite distribution sampling functions -float sample_uniform(float start, float end, uint32_t* seed); -float sample_normal(float mean, float sigma, uint32_t* seed); -float sample_lognormal(float logmean, float logsigma, uint32_t* seed); -float sample_to(float low, float high, uint32_t* seed); +float sample_uniform(float start, float end, uint64_t* seed); +float sample_normal(float mean, float sigma, uint64_t* seed); +float sample_lognormal(float logmean, float logsigma, uint64_t* seed); +float sample_to(float low, float high, uint64_t* seed); -float sample_gamma(float alpha, uint32_t* seed); -float sample_beta(float a, float b, uint32_t* seed); +float sample_gamma(float alpha, uint64_t* seed); +float sample_beta(float a, float b, uint64_t* seed); // Array helpers float array_sum(float* array, int length); @@ -27,7 +27,7 @@ float array_mean(float* array, int length); float array_std(float* array, int length); // Mixture function -float sample_mixture(float (*samplers[])(uint32_t*), float* weights, int n_dists, uint32_t* seed); +float sample_mixture(float (*samplers[])(uint64_t*), float* weights, int n_dists, uint64_t* seed); // Box struct box { @@ -47,7 +47,7 @@ struct box inverse_cdf_float(float cdf(float), float p); struct box inverse_cdf_box(struct box cdf_box(float), float p); // Samplers from cdf -struct box sampler_cdf_float(float cdf(float), uint32_t* seed); -struct box sampler_cdf_box(struct box cdf(float), uint32_t* seed); +struct box sampler_cdf_float(float cdf(float), uint64_t* seed); +struct box sampler_cdf_box(struct box cdf(float), uint64_t* seed); #endif diff --git a/test/test b/test/test Binary files differ. diff --git a/test/test.c b/test/test.c @@ -4,9 +4,9 @@ #include <stdlib.h> #include <stdio.h> -#define N 10 * 1000 * 1000 +#define N 1000 * 1000 -void test_unit_uniform(uint32_t* seed){ +void test_unit_uniform(uint64_t* seed){ float* unit_uniform_array = malloc(sizeof(float) * N); for(int i=0; i<N; i++){ @@ -40,7 +40,7 @@ void test_unit_uniform(uint32_t* seed){ } -void test_uniform(float start, float end, uint32_t* seed){ +void test_uniform(float start, float end, uint64_t* seed){ float* uniform_array = malloc(sizeof(float) * N); for(int i=0; i<N; i++){ @@ -76,7 +76,7 @@ void test_uniform(float start, float end, uint32_t* seed){ int main(){ // set randomness seed - uint32_t* seed = malloc(sizeof(uint32_t)); + uint64_t* seed = malloc(sizeof(uint64_t)); *seed = 1000; // xorshift can't start with a seed of 0 test_unit_uniform(seed);