1570af302Sopenharmony_ci#include <stdint.h>
2570af302Sopenharmony_ci#include <stdlib.h>
3570af302Sopenharmony_ci#include <stdio.h>
4570af302Sopenharmony_ci#include <errno.h>
5570af302Sopenharmony_ci#include <unistd.h>
6570af302Sopenharmony_ci
7570af302Sopenharmony_cistatic uint64_t seed = -1;
8570af302Sopenharmony_cistatic uint32_t rand32(void)
9570af302Sopenharmony_ci{
10570af302Sopenharmony_ci	seed = 6364136223846793005ull*seed + 1;
11570af302Sopenharmony_ci	return seed >> 32;
12570af302Sopenharmony_ci}
13570af302Sopenharmony_cistatic uint64_t rand64(void)
14570af302Sopenharmony_ci{
15570af302Sopenharmony_ci	uint64_t u = rand32();
16570af302Sopenharmony_ci	return u<<32 | rand32();
17570af302Sopenharmony_ci}
18570af302Sopenharmony_cistatic double frand(){return rand64() * 0x1p-64;}
19570af302Sopenharmony_cistatic float frandf(){return rand32() * 0x1p-32f;}
20570af302Sopenharmony_cistatic long double frandl(){return rand64() * 0x1p-64L;}
21570af302Sopenharmony_ci
22570af302Sopenharmony_ci/* uniform random in [0,n), n > 0 must hold */
23570af302Sopenharmony_ciuint64_t randn(uint64_t n)
24570af302Sopenharmony_ci{
25570af302Sopenharmony_ci	uint64_t r, m;
26570af302Sopenharmony_ci
27570af302Sopenharmony_ci	/* m is the largest multiple of n */
28570af302Sopenharmony_ci	m = -1;
29570af302Sopenharmony_ci	m -= m%n;
30570af302Sopenharmony_ci	while ((r = rand64()) >= m);
31570af302Sopenharmony_ci	return r%n;
32570af302Sopenharmony_ci}
33570af302Sopenharmony_ci
34570af302Sopenharmony_ci/* uniform on [a,b] */
35570af302Sopenharmony_ciuint64_t randint(uint64_t a, uint64_t b)
36570af302Sopenharmony_ci{
37570af302Sopenharmony_ci	if (b < a) {
38570af302Sopenharmony_ci		uint64_t t = b;
39570af302Sopenharmony_ci		b = a;
40570af302Sopenharmony_ci		a = t;
41570af302Sopenharmony_ci	}
42570af302Sopenharmony_ci	return a + randn(b - a + 1);
43570af302Sopenharmony_ci}
44570af302Sopenharmony_ci
45570af302Sopenharmony_ciint insert(uint64_t *tab, size_t len, uint64_t v)
46570af302Sopenharmony_ci{
47570af302Sopenharmony_ci	size_t i = v & (len-1);
48570af302Sopenharmony_ci	size_t j = 1;
49570af302Sopenharmony_ci
50570af302Sopenharmony_ci	/* 0 means empty, v > 0 must hold */
51570af302Sopenharmony_ci	while (tab[i]) {
52570af302Sopenharmony_ci		if (tab[i] == v)
53570af302Sopenharmony_ci			return -1;
54570af302Sopenharmony_ci		i += j++;
55570af302Sopenharmony_ci		i &= len-1;
56570af302Sopenharmony_ci	}
57570af302Sopenharmony_ci	tab[i] = v;
58570af302Sopenharmony_ci	return 0;
59570af302Sopenharmony_ci}
60570af302Sopenharmony_ci
61570af302Sopenharmony_cistatic void shuffle2(uint64_t *p, uint64_t *q, size_t np, size_t nq)
62570af302Sopenharmony_ci{
63570af302Sopenharmony_ci	size_t i,r,t;
64570af302Sopenharmony_ci
65570af302Sopenharmony_ci	i = np+nq;
66570af302Sopenharmony_ci	while (i > np) {
67570af302Sopenharmony_ci		r = randn(i);
68570af302Sopenharmony_ci		i--;
69570af302Sopenharmony_ci		t = q[i-np];
70570af302Sopenharmony_ci		if (r < np) {
71570af302Sopenharmony_ci			q[i-np] = p[r];
72570af302Sopenharmony_ci			p[r] = t;
73570af302Sopenharmony_ci		} else {
74570af302Sopenharmony_ci			q[i-np] = q[r-np];
75570af302Sopenharmony_ci			q[r-np] = t;
76570af302Sopenharmony_ci		}
77570af302Sopenharmony_ci	}
78570af302Sopenharmony_ci}
79570af302Sopenharmony_ci
80570af302Sopenharmony_ci/* choose k unique numbers from [0,n), k <= n */
81570af302Sopenharmony_ciint choose(uint64_t n, size_t k, uint64_t *p)
82570af302Sopenharmony_ci{
83570af302Sopenharmony_ci	uint64_t *tab;
84570af302Sopenharmony_ci	size_t i, j, len;
85570af302Sopenharmony_ci
86570af302Sopenharmony_ci	if (n < k)
87570af302Sopenharmony_ci		return -1;
88570af302Sopenharmony_ci
89570af302Sopenharmony_ci	if (n < 16) {
90570af302Sopenharmony_ci		/* no alloc */
91570af302Sopenharmony_ci		while (k)
92570af302Sopenharmony_ci			if (randn(n--) < k)
93570af302Sopenharmony_ci				p[--k] = n;
94570af302Sopenharmony_ci		return 0;
95570af302Sopenharmony_ci	}
96570af302Sopenharmony_ci
97570af302Sopenharmony_ci	if (k < 8) {
98570af302Sopenharmony_ci		/* no alloc, n > 15 > 2*k */
99570af302Sopenharmony_ci		for (i = 0; i < k;) {
100570af302Sopenharmony_ci			p[i] = randn(n);
101570af302Sopenharmony_ci			for (j = 0; p[j] != p[i]; j++);
102570af302Sopenharmony_ci			if (j == i)
103570af302Sopenharmony_ci				i++;
104570af302Sopenharmony_ci		}
105570af302Sopenharmony_ci		return 0;
106570af302Sopenharmony_ci	}
107570af302Sopenharmony_ci
108570af302Sopenharmony_ci	if (n < 5*k && (n-k)*sizeof *tab < (size_t)-1) {
109570af302Sopenharmony_ci		/* allocation is < 4*k */
110570af302Sopenharmony_ci		tab = malloc((n-k) * sizeof *tab);
111570af302Sopenharmony_ci		if (!tab)
112570af302Sopenharmony_ci			return -1;
113570af302Sopenharmony_ci		for (i = 0; i < k; i++)
114570af302Sopenharmony_ci			p[i] = i;
115570af302Sopenharmony_ci		for (; i < n; i++)
116570af302Sopenharmony_ci			tab[i-k] = i;
117570af302Sopenharmony_ci		if (n-k < k)
118570af302Sopenharmony_ci			shuffle2(p, tab, k, n-k);
119570af302Sopenharmony_ci		else
120570af302Sopenharmony_ci			shuffle2(tab, p, n-k, k);
121570af302Sopenharmony_ci		free(tab);
122570af302Sopenharmony_ci		return 0;
123570af302Sopenharmony_ci	}
124570af302Sopenharmony_ci
125570af302Sopenharmony_ci	/* allocation is < 4*k */
126570af302Sopenharmony_ci	for (len = 16; len <= 2*k; len *= 2);
127570af302Sopenharmony_ci	tab = calloc(len, sizeof *tab);
128570af302Sopenharmony_ci	if (!tab)
129570af302Sopenharmony_ci		return -1;
130570af302Sopenharmony_ci	for (i = 0; i < k; i++)
131570af302Sopenharmony_ci		while (insert(tab, len, randn(n)+1));
132570af302Sopenharmony_ci	for (i = 0; i < len; i++)
133570af302Sopenharmony_ci		if (tab[i])
134570af302Sopenharmony_ci			*p++ = tab[i]-1;
135570af302Sopenharmony_ci	free(tab);
136570af302Sopenharmony_ci	return 0;
137570af302Sopenharmony_ci}
138570af302Sopenharmony_ci
139570af302Sopenharmony_cistatic int cmp64(const void *a, const void *b)
140570af302Sopenharmony_ci{
141570af302Sopenharmony_ci	const uint64_t *ua = a, *ub = b;
142570af302Sopenharmony_ci	return *ua < *ub ? -1 : (*ua > *ub ? 1 : 0);
143570af302Sopenharmony_ci}
144570af302Sopenharmony_ci
145570af302Sopenharmony_ci// todo: in place flip problem
146570af302Sopenharmony_ci
147570af302Sopenharmony_ci/* choose k unique uint64_t numbers */
148570af302Sopenharmony_ciint choose64(size_t k, uint64_t *p)
149570af302Sopenharmony_ci{
150570af302Sopenharmony_ci	size_t i, c;
151570af302Sopenharmony_ci
152570af302Sopenharmony_ci	/* no alloc, collisions should be very rare */
153570af302Sopenharmony_ci	for (i = 0; i < k; i++)
154570af302Sopenharmony_ci		p[i] = rand64();
155570af302Sopenharmony_ci	do {
156570af302Sopenharmony_ci		c = 0;
157570af302Sopenharmony_ci		qsort(p, k, sizeof *p, cmp64);
158570af302Sopenharmony_ci		for (i = 1; i < k; i++)
159570af302Sopenharmony_ci			if (p[i] == p[i-1]) {
160570af302Sopenharmony_ci				p[i-1] = rand64();
161570af302Sopenharmony_ci				c = 1;
162570af302Sopenharmony_ci			}
163570af302Sopenharmony_ci	} while (c);
164570af302Sopenharmony_ci	return 0;
165570af302Sopenharmony_ci}
166570af302Sopenharmony_ci
167570af302Sopenharmony_ci/* equidistant sampling with some randomness */
168570af302Sopenharmony_ciint sample(uint64_t n, size_t k, uint64_t *p)
169570af302Sopenharmony_ci{
170570af302Sopenharmony_ci	uint64_t a = 0;
171570af302Sopenharmony_ci	uint64_t d = n/k;
172570af302Sopenharmony_ci	size_t m = n%k;
173570af302Sopenharmony_ci	size_t i, j;
174570af302Sopenharmony_ci	uint64_t *q;
175570af302Sopenharmony_ci
176570af302Sopenharmony_ci	if (!d)
177570af302Sopenharmony_ci		return -1;
178570af302Sopenharmony_ci	q = malloc((m+1) * sizeof *q);
179570af302Sopenharmony_ci	if (!q)
180570af302Sopenharmony_ci		return -1;
181570af302Sopenharmony_ci	if (choose(k, m, q))
182570af302Sopenharmony_ci		return -1;
183570af302Sopenharmony_ci	qsort(q, m, sizeof *q, cmp64);
184570af302Sopenharmony_ci	q[m] = k;
185570af302Sopenharmony_ci	for (i = j = 0; i < k; i++) {
186570af302Sopenharmony_ci		uint64_t t;
187570af302Sopenharmony_ci
188570af302Sopenharmony_ci		while (q[j] < i)
189570af302Sopenharmony_ci			j++;
190570af302Sopenharmony_ci		if (q[j] == i)
191570af302Sopenharmony_ci			t = d+1;
192570af302Sopenharmony_ci		else
193570af302Sopenharmony_ci			t = d;
194570af302Sopenharmony_ci		p[i] = a + randn(t);
195570af302Sopenharmony_ci		a += t;
196570af302Sopenharmony_ci	}
197570af302Sopenharmony_ci	free(q);
198570af302Sopenharmony_ci	return 0;
199570af302Sopenharmony_ci}
200570af302Sopenharmony_ci
201570af302Sopenharmony_ci/* [-inf,inf] uniform on representation */
202570af302Sopenharmony_ciint genall(size_t k, uint64_t *p)
203570af302Sopenharmony_ci{
204570af302Sopenharmony_ci	size_t i;
205570af302Sopenharmony_ci	uint64_t n, d;
206570af302Sopenharmony_ci	d = 1;
207570af302Sopenharmony_ci	d <<= 52;
208570af302Sopenharmony_ci	if (sample(-2*d, k, p))
209570af302Sopenharmony_ci		return -1;
210570af302Sopenharmony_ci	n = 0x7ff;
211570af302Sopenharmony_ci	n <<= 52;
212570af302Sopenharmony_ci	for (i = 0; i < k; i++)
213570af302Sopenharmony_ci		if (p[i] > n)
214570af302Sopenharmony_ci			p[i] += d-1;
215570af302Sopenharmony_ci	return 0;
216570af302Sopenharmony_ci}
217570af302Sopenharmony_ci
218570af302Sopenharmony_ci/* [a,b) uniform on representation, 0 <= a <= b */
219570af302Sopenharmony_ciint genab(size_t k, uint64_t a, uint64_t b, uint64_t *p)
220570af302Sopenharmony_ci{
221570af302Sopenharmony_ci	size_t i;
222570af302Sopenharmony_ci
223570af302Sopenharmony_ci	if (sample(b-a, k, p))
224570af302Sopenharmony_ci		return -1;
225570af302Sopenharmony_ci	for (i = 0; i < k; i++)
226570af302Sopenharmony_ci		p[i] += a;
227570af302Sopenharmony_ci	return 0;
228570af302Sopenharmony_ci}
229570af302Sopenharmony_ci
230570af302Sopenharmony_ci#define asfloat(x) ((union{uint64_t af_i; double af_f;}){.af_i=x}.af_f)
231570af302Sopenharmony_ci#define asint(x)   ((union{uint64_t af_i; double af_f;}){.af_f=x}.af_i)
232570af302Sopenharmony_ci
233570af302Sopenharmony_ciint main(int argc, char *argv[])
234570af302Sopenharmony_ci{
235570af302Sopenharmony_ci	uint64_t k, i;
236570af302Sopenharmony_ci	uint64_t *p;
237570af302Sopenharmony_ci	double a,b,m;
238570af302Sopenharmony_ci	char *e;
239570af302Sopenharmony_ci	int opt;
240570af302Sopenharmony_ci
241570af302Sopenharmony_ci	k = 1000;
242570af302Sopenharmony_ci	a = 0;
243570af302Sopenharmony_ci	b = 1;
244570af302Sopenharmony_ci	m = 1;
245570af302Sopenharmony_ci	while ((opt = getopt(argc, argv, "n:a:b:m:s:")) != -1) {
246570af302Sopenharmony_ci		switch(opt) {
247570af302Sopenharmony_ci		case 'n':
248570af302Sopenharmony_ci			k = strtoull(optarg,&e,0);
249570af302Sopenharmony_ci			break;
250570af302Sopenharmony_ci		case 'a':
251570af302Sopenharmony_ci			a = strtod(optarg,&e);
252570af302Sopenharmony_ci			if (a < 0)
253570af302Sopenharmony_ci				goto usage;
254570af302Sopenharmony_ci			break;
255570af302Sopenharmony_ci		case 'b':
256570af302Sopenharmony_ci			b = strtod(optarg,&e);
257570af302Sopenharmony_ci			if (b < 0)
258570af302Sopenharmony_ci				goto usage;
259570af302Sopenharmony_ci			break;
260570af302Sopenharmony_ci		case 'm':
261570af302Sopenharmony_ci			m = strtod(optarg,&e);
262570af302Sopenharmony_ci			break;
263570af302Sopenharmony_ci		case 's':
264570af302Sopenharmony_ci			seed = strtoull(optarg,&e,0);
265570af302Sopenharmony_ci			break;
266570af302Sopenharmony_ci		default:
267570af302Sopenharmony_ciusage:
268570af302Sopenharmony_ci			fprintf(stderr, "usage: %s -n num -a absmin -b absmax -m mult -s seed\n", argv[0]);
269570af302Sopenharmony_ci			return -1;
270570af302Sopenharmony_ci		}
271570af302Sopenharmony_ci		if (*e || errno)
272570af302Sopenharmony_ci			goto usage;
273570af302Sopenharmony_ci	}
274570af302Sopenharmony_ci	if (!(a <= b))
275570af302Sopenharmony_ci		goto usage;
276570af302Sopenharmony_ci	p = malloc(k * sizeof *p);
277570af302Sopenharmony_ci	if (!p)
278570af302Sopenharmony_ci		return -1;
279570af302Sopenharmony_ci	if (genab(k, asint(a), asint(b), p))
280570af302Sopenharmony_ci//	if (genall(k,p))
281570af302Sopenharmony_ci		return -1;
282570af302Sopenharmony_ci	for (i = 0; i < k; i++)
283570af302Sopenharmony_ci//		printf("0x%016llx\n", p[i]);
284570af302Sopenharmony_ci		printf("%a\n", m*asfloat(p[i]));
285570af302Sopenharmony_ci	return 0;
286570af302Sopenharmony_ci}
287