#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
static uint64_t seed = -1;
static uint32_t rand32(void)
{
seed = 6364136223846793005ull*seed + 1;
return seed >> 32;
}
static uint64_t rand64(void)
{
uint64_t u = rand32();
return u<<32 | rand32();
}
static double frand(){return rand64() * 0x1p-64;}
static float frandf(){return rand32() * 0x1p-32f;}
static long double frandl(){return rand64() * 0x1p-64L;}
/* uniform random in [0,n), n > 0 must hold */
uint64_t randn(uint64_t n)
{
uint64_t r, m;
/* m is the largest multiple of n */
m = -1;
m -= m%n;
while ((r = rand64()) >= m);
return r%n;
}
/* uniform on [a,b] */
uint64_t randint(uint64_t a, uint64_t b)
{
if (b < a) {
uint64_t t = b;
b = a;
a = t;
}
return a + randn(b - a + 1);
}
int insert(uint64_t *tab, size_t len, uint64_t v)
{
size_t i = v & (len-1);
size_t j = 1;
/* 0 means empty, v > 0 must hold */
while (tab[i]) {
if (tab[i] == v)
return -1;
i += j++;
i &= len-1;
}
tab[i] = v;
return 0;
}
static void shuffle2(uint64_t *p, uint64_t *q, size_t np, size_t nq)
{
size_t i,r,t;
i = np+nq;
while (i > np) {
r = randn(i);
i--;
t = q[i-np];
if (r < np) {
q[i-np] = p[r];
p[r] = t;
} else {
q[i-np] = q[r-np];
q[r-np] = t;
}
}
}
/* choose k unique numbers from [0,n), k <= n */
int choose(uint64_t n, size_t k, uint64_t *p)
{
uint64_t *tab;
size_t i, j, len;
if (n < k)
return -1;
if (n < 16) {
/* no alloc */
while (k)
if (randn(n--) < k)
p[--k] = n;
return 0;
}
if (k < 8) {
/* no alloc, n > 15 > 2*k */
for (i = 0; i < k;) {
p[i] = randn(n);
for (j = 0; p[j] != p[i]; j++);
if (j == i)
i++;
}
return 0;
}
if (n < 5*k && (n-k)*sizeof *tab < (size_t)-1) {
/* allocation is < 4*k */
tab = malloc((n-k) * sizeof *tab);
if (!tab)
return -1;
for (i = 0; i < k; i++)
p[i] = i;
for (; i < n; i++)
tab[i-k] = i;
if (n-k < k)
shuffle2(p, tab, k, n-k);
else
shuffle2(tab, p, n-k, k);
free(tab);
return 0;
}
/* allocation is < 4*k */
for (len = 16; len <= 2*k; len *= 2);
tab = calloc(len, sizeof *tab);
if (!tab)
return -1;
for (i = 0; i < k; i++)
while (insert(tab, len, randn(n)+1));
for (i = 0; i < len; i++)
if (tab[i])
*p++ = tab[i]-1;
free(tab);
return 0;
}
static int cmp64(const void *a, const void *b)
{
const uint64_t *ua = a, *ub = b;
return *ua < *ub ? -1 : (*ua > *ub ? 1 : 0);
}
// todo: in place flip problem
/* choose k unique uint64_t numbers */
int choose64(size_t k, uint64_t *p)
{
size_t i, c;
/* no alloc, collisions should be very rare */
for (i = 0; i < k; i++)
p[i] = rand64();
do {
c = 0;
qsort(p, k, sizeof *p, cmp64);
for (i = 1; i < k; i++)
if (p[i] == p[i-1]) {
p[i-1] = rand64();
c = 1;
}
} while (c);
return 0;
}
/* equidistant sampling with some randomness */
int sample(uint64_t n, size_t k, uint64_t *p)
{
uint64_t a = 0;
uint64_t d = n/k;
size_t m = n%k;
size_t i, j;
uint64_t *q;
if (!d)
return -1;
q = malloc((m+1) * sizeof *q);
if (!q)
return -1;
if (choose(k, m, q))
return -1;
qsort(q, m, sizeof *q, cmp64);
q[m] = k;
for (i = j = 0; i < k; i++) {
uint64_t t;
while (q[j] < i)
j++;
if (q[j] == i)
t = d+1;
else
t = d;
p[i] = a + randn(t);
a += t;
}
free(q);
return 0;
}
/* [-inf,inf] uniform on representation */
int genall(size_t k, uint64_t *p)
{
size_t i;
uint64_t n, d;
d = 1;
d <<= 52;
if (sample(-2*d, k, p))
return -1;
n = 0x7ff;
n <<= 52;
for (i = 0; i < k; i++)
if (p[i] > n)
p[i] += d-1;
return 0;
}
/* [a,b) uniform on representation, 0 <= a <= b */
int genab(size_t k, uint64_t a, uint64_t b, uint64_t *p)
{
size_t i;
if (sample(b-a, k, p))
return -1;
for (i = 0; i < k; i++)
p[i] += a;
return 0;
}
#define asfloat(x) ((union{uint64_t af_i; double af_f;}){.af_i=x}.af_f)
#define asint(x) ((union{uint64_t af_i; double af_f;}){.af_f=x}.af_i)
int main(int argc, char *argv[])
{
uint64_t k, i;
uint64_t *p;
double a,b,m;
char *e;
int opt;
k = 1000;
a = 0;
b = 1;
m = 1;
while ((opt = getopt(argc, argv, "n:a:b:m:s:")) != -1) {
switch(opt) {
case 'n':
k = strtoull(optarg,&e,0);
break;
case 'a':
a = strtod(optarg,&e);
if (a < 0)
goto usage;
break;
case 'b':
b = strtod(optarg,&e);
if (b < 0)
goto usage;
break;
case 'm':
m = strtod(optarg,&e);
break;
case 's':
seed = strtoull(optarg,&e,0);
break;
default:
usage:
fprintf(stderr, "usage: %s -n num -a absmin -b absmax -m mult -s seed\n", argv[0]);
return -1;
}
if (*e || errno)
goto usage;
}
if (!(a <= b))
goto usage;
p = malloc(k * sizeof *p);
if (!p)
return -1;
if (genab(k, asint(a), asint(b), p))
// if (genall(k,p))
return -1;
for (i = 0; i < k; i++)
// printf("0x%016llx\n", p[i]);
printf("%a\n", m*asfloat(p[i]));
return 0;
}