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