feat: rand not thread safe, use rand_r throughout

This commit is contained in:
NunoSempere 2023-06-02 12:44:36 -06:00
parent 3f0ec8be0e
commit 58c74ce37d
2 changed files with 34 additions and 37 deletions

Binary file not shown.

View File

@ -6,7 +6,7 @@
const float PI = 3.14159265358979323846;
#define N 1000000
#define N 100000000
//Array helpers
@ -47,54 +47,42 @@ void array_cumsum(float* array_to_sum, float* array_cumsummed, int length)
}
}
float rand_float(float to)
float rand_float(float to, unsigned int* seed)
{
return ((float)rand() / (float)RAND_MAX) * to;
return ((float)rand_r(seed) / (float)RAND_MAX) * to;
}
float ur_normal()
float ur_normal(unsigned int* seed)
{
float u1 = rand_float(1.0);
float u2 = rand_float(1.0);
float u1 = rand_float(1.0, seed);
float u2 = rand_float(1.0, seed);
float z = sqrtf(-2.0 * log(u1)) * sin(2 * PI * u2);
return z;
}
inline float random_uniform(float from, float to)
inline float random_uniform(float from, float to, unsigned int* seed)
{
return ((float)rand() / (float)RAND_MAX) * (to - from) + from;
return ((float) rand_r(seed) / (float)RAND_MAX) * (to - from) + from;
}
inline float random_normal(float mean, float sigma)
inline float random_normal(float mean, float sigma, unsigned int* seed)
{
return (mean + sigma * ur_normal());
return (mean + sigma * ur_normal(seed));
}
inline float random_lognormal(float logmean, float logsigma)
inline float random_lognormal(float logmean, float logsigma, unsigned int* seed)
{
return expf(random_normal(logmean, logsigma));
return expf(random_normal(logmean, logsigma, seed));
}
inline float random_to(float low, float high)
inline float random_to(float low, float high, unsigned int* seed)
{
const float NORMAL95CONFIDENCE = 1.6448536269514722;
float loglow = logf(low);
float loghigh = logf(high);
float logmean = (loglow + loghigh) / 2;
float logsigma = (loghigh - loglow) / (2.0 * NORMAL95CONFIDENCE);
return random_lognormal(logmean, logsigma);
}
void array_random_to(float* array, int length, float low, float high)
{
int i;
#pragma omp private(i)
{
#pragma omp for
for (i = 0; i < length; i++) {
array[i] = random_to(low, high);
}
}
return random_lognormal(logmean, logsigma, seed);
}
int split_array_get_my_length(int index, int total_length, int n_threads)
@ -103,6 +91,7 @@ int split_array_get_my_length(int index, int total_length, int n_threads)
}
//Old version, don't use it!! Optimized version is called mixture_f. This one is just for display
/*
void mixture(float* dists[], float* weights, int n_dists, float* results)
{
float sum_weights = array_sum(weights, n_dists);
@ -145,8 +134,8 @@ void mixture(float* dists[], float* weights, int n_dists, float* results)
free(normalized_weights);
free(cummulative_weights);
}
void mixture_f(float (*samplers[])(void), float* weights, int n_dists, float** results, int n_threads)
*/
void mixture_f(float (*samplers[])(unsigned int* ), float* weights, int n_dists, float** results, int n_threads)
{
float sum_weights = array_sum(weights, n_dists);
float* normalized_weights = malloc(n_dists * sizeof(float));
@ -160,6 +149,11 @@ void mixture_f(float (*samplers[])(void), float* weights, int n_dists, float** r
//create var holders
float p1;
int sample_index, i, own_length;
unsigned int* seeds[n_threads];
for(unsigned int i=0; i<n_threads; i++){
seeds[i] = malloc(sizeof(unsigned int));
*seeds[i] = i;
}
#pragma omp parallel private(i, p1, sample_index, own_length)
{
@ -167,10 +161,10 @@ void mixture_f(float (*samplers[])(void), float* weights, int n_dists, float** r
for (i = 0; i < n_threads; i++) {
own_length = split_array_get_my_length(i, N, n_threads);
for (int j = 0; j < own_length; j++) {
p1 = random_uniform(0, 1);
p1 = random_uniform(0, 1, seeds[i]);
for (int k = 0; k < n_dists; k++) {
if (p1 < cummulative_weights[k]) {
results[i][j] = samplers[k]();
results[i][j] = samplers[k](seeds[i]);
break;
}
}
@ -179,26 +173,29 @@ void mixture_f(float (*samplers[])(void), float* weights, int n_dists, float** r
}
free(normalized_weights);
free(cummulative_weights);
for(unsigned int i=0; i<n_threads; i++){
free(seeds[i]);
}
}
float sample_0()
float sample_0(unsigned int* seed)
{
return 0;
}
float sample_1()
float sample_1(unsigned int* seed)
{
return 1;
}
float sample_few()
float sample_few(unsigned int* seed)
{
return random_to(1, 3);
return random_to(1, 3, seed);
}
float sample_many()
float sample_many(unsigned int* seed)
{
return random_to(2, 10);
return random_to(2, 10, seed);
}
void split_array_allocate(float** meta_array, int length, int divide_into)
@ -265,7 +262,7 @@ int main()
// Generate mixture
int n_dists = 4;
float weights[] = { 1 - p_c, p_c / 2, p_c / 4, p_c / 4 };
float (*samplers[])(void) = { sample_0, sample_1, sample_few, sample_many };
float (*samplers[])(unsigned int* ) = { sample_0, sample_1, sample_few, sample_many };
mixture_f(samplers, weights, n_dists, dist_mixture, n_threads);
printf("Sum(dist_mixture, N)/N = %f\n", split_array_sum(dist_mixture, N, n_threads) / N);