64 lines
1.1 KiB
C
64 lines
1.1 KiB
C
#include <math.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "../hash.h"
|
|
#include "gauss.h"
|
|
|
|
#define GAUSS_ITERS 12
|
|
|
|
static int gauss_dev(struct gauss_state *gs)
|
|
{
|
|
unsigned int r;
|
|
int vr;
|
|
|
|
if (!gs->stddev)
|
|
return 0;
|
|
|
|
r = __rand(&gs->r);
|
|
vr = gs->stddev * (r / (FRAND32_MAX + 1.0));
|
|
|
|
return vr - gs->stddev / 2;
|
|
}
|
|
|
|
unsigned long long gauss_next(struct gauss_state *gs)
|
|
{
|
|
unsigned long long sum = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < GAUSS_ITERS; i++)
|
|
sum += __rand(&gs->r) % (gs->nranges + 1);
|
|
|
|
sum = (sum + GAUSS_ITERS - 1) / GAUSS_ITERS;
|
|
|
|
if (gs->stddev) {
|
|
int dev = gauss_dev(gs);
|
|
|
|
while (dev + sum >= gs->nranges)
|
|
dev /= 2;
|
|
sum += dev;
|
|
}
|
|
|
|
if (!gs->disable_hash)
|
|
sum = __hash_u64(sum);
|
|
|
|
return sum % gs->nranges;
|
|
}
|
|
|
|
void gauss_init(struct gauss_state *gs, unsigned long nranges, double dev,
|
|
unsigned int seed)
|
|
{
|
|
memset(gs, 0, sizeof(*gs));
|
|
init_rand_seed(&gs->r, seed, 0);
|
|
gs->nranges = nranges;
|
|
|
|
if (dev != 0.0) {
|
|
gs->stddev = ceil((double) (nranges * 100.0) / dev);
|
|
if (gs->stddev > nranges / 2)
|
|
gs->stddev = nranges / 2;
|
|
}
|
|
}
|
|
|
|
void gauss_disable_hash(struct gauss_state *gs)
|
|
{
|
|
gs->disable_hash = true;
|
|
}
|