|
#define _DEFAULT_SOURCE 1 |
|
|
|
#include <math.h> |
|
#include <stdbool.h> |
|
#include <stdint.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <time.h> |
|
|
|
struct random_state { |
|
uint64_t state; |
|
uint64_t inc; |
|
}; |
|
|
|
static float random_next(struct random_state *st) { |
|
uint64_t s = st->state; |
|
st->state = s * 6364136223846793005ull + st->inc; |
|
uint32_t x = ((s >> 18) ^ s) >> 27; |
|
uint32_t r = s >> 59; |
|
uint32_t v = (x >> r) | (x << ((-r) & 31)); |
|
return (float)v * (1.0f / 4294967296.0f); |
|
} |
|
|
|
// Generate a point in the unit sphere, uniformly. |
|
void rejection_sample(struct random_state *st, int n, float *arr) { |
|
for (int i = 0; i < n;) { |
|
float x = random_next(st) * 2.0f - 1.0f; |
|
float y = random_next(st) * 2.0f - 1.0f; |
|
float z = random_next(st) * 2.0f - 1.0f; |
|
if (x * x + y * y + z * z <= 1) { |
|
arr[3 * i] = x; |
|
arr[3 * i + 1] = y; |
|
arr[3 * i + 2] = z; |
|
i++; |
|
} |
|
} |
|
} |
|
|
|
// Generate a point in the unit sphere, uniformly. |
|
void polar_sample(struct random_state *st, int n, float *arr) { |
|
for (int i = 0; i < n; i++) { |
|
float z = random_next(st) * 2.0f - 1.0f; |
|
float angle = (8.0f * atanf(1.0f)) * random_next(st); |
|
float z_scale = cbrtf(random_next(st)); |
|
float xy_scale = z_scale * sqrtf(1.0f - z * z); |
|
arr[3 * i] = cosf(angle) * xy_scale; |
|
arr[3 * i + 1] = cosf(angle) * xy_scale; |
|
arr[3 * i + 2] = z * z_scale; |
|
} |
|
} |
|
|
|
typedef void (*sample_func)(struct random_state *st, int n, float *arr); |
|
|
|
void benchmark(const char *name, int runs, int iter, int n, sample_func func) { |
|
float *arr = malloc(n * 3 * sizeof(float)); |
|
if (arr == NULL) { |
|
abort(); |
|
} |
|
double *times = malloc(runs * sizeof(double)); |
|
if (times == NULL) { |
|
abort(); |
|
} |
|
struct random_state st = {.state = 1, .inc = 1}; |
|
func(&st, n, arr); |
|
for (int i = 0; i < runs; i++) { |
|
struct timespec t0, t1; |
|
clock_gettime(CLOCK_MONOTONIC, &t0); |
|
for (int j = 0; j < iter; j++) { |
|
func(&st, n, arr); |
|
} |
|
clock_gettime(CLOCK_MONOTONIC, &t1); |
|
times[i] = (double)(t1.tv_sec - t0.tv_sec) + |
|
1.0e-9 * (double)(t1.tv_nsec - t0.tv_nsec); |
|
} |
|
double sum = 0.0; |
|
for (int i = 0; i < runs; i++) { |
|
sum += times[i]; |
|
} |
|
double mean = sum / (double)runs; |
|
sum = 0.0; |
|
for (int i = 0; i < runs; i++) { |
|
double delta = times[i] - mean; |
|
sum += delta * delta; |
|
} |
|
double var = sum / (double)runs; |
|
printf("%s: %.1f ns/sample, ±%.1f ns/sample\n", name, |
|
mean * 1.0e9 / (double)(iter * n), |
|
sqrt(var) * 1.0e9 / (double)(iter * n)); |
|
free(arr); |
|
free(times); |
|
} |
|
|
|
int main(int argc, char**argv) { |
|
(void)argc; |
|
(void)argv; |
|
benchmark("rejection", 1000, 100, 1000, rejection_sample); |
|
benchmark("polar", 1000, 100, 1000, polar_sample); |
|
return 0; |
|
} |