Skip to content

Instantly share code, notes, and snippets.

@alwynallan
Created February 23, 2021 21:51
Show Gist options
  • Save alwynallan/a15ce329e8e0efcacf1eeffe4e9431e7 to your computer and use it in GitHub Desktop.
Save alwynallan/a15ce329e8e0efcacf1eeffe4e9431e7 to your computer and use it in GitHub Desktop.
Tests the 64-bit hardware efficient generation of random 1-in-3 choices.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
// alwynallan@gmail.com February 2021
// tests the 64-bit hardware efficient generation of 1-in-3 choices.
// uses the fact that 2^65 is just ~1% larger than 3^41
// whereas 2^2 is 25% larger than 3^1
// compile: gcc -Wall thirds.c -o thirds
uint64_t random64() {
static FILE * fr = NULL;
uint64_t res;
if(fr == NULL) {
fr = fopen("/dev/urandom","r");
assert(fr != NULL);
}
fread(&res, sizeof(uint64_t), 1, fr);
return res;
}
int thirds() {
static uint64_t thirds_res;
static int thirds_res_level = 0; // how many times thirds_res can be div/mod cycled 0-40
static uint64_t bits;
static int bits_level = 0; // how many unused bits 0-64
if(thirds_res_level) {
int res = thirds_res % 3;
thirds_res /= 3;
thirds_res_level--;
return res;
}
while(1) {
uint64_t n64 = random64();
if(!bits_level) {
bits = random64();
bits_level = 64;
}
int bit = bits & 1;
bits = bits >> 1;
bits_level--;
if(bit) {
if(n64 <= 18026252303461234787u){ // big number is 3^41 - 2^64
thirds_res = 6148914691236517205u + n64 / 3; // big number is 2^64 / 3
int res = n64 % 3 + 1; // 1 here is 2^64 % 3
if(res == 3) {
thirds_res++;
res = 0;
}
thirds_res_level = 40;
return res;
} // else go for another loop
}
else {
thirds_res = n64 / 3;
thirds_res_level = 40;
return n64 % 3;
}
} // no guarantee it will return, but 99% chance each loop
}
int main() {
unsigned bins[3] = {0, 0, 0};
for(int i = 0; i < 1000; i++) printf("%d ", thirds());
for(unsigned i = 0; i < 3000000000; i++) bins[thirds()]++;
printf("\n%u, %u, %u\n", bins[0], bins[1], bins[2]);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment