1570af302Sopenharmony_ci#include <float.h> 2570af302Sopenharmony_ci#include <stdint.h> 3570af302Sopenharmony_ci#include <stdlib.h> 4570af302Sopenharmony_ci 5570af302Sopenharmony_ci// TODO: use large period prng 6570af302Sopenharmony_cistatic uint64_t seed = -1; 7570af302Sopenharmony_cistatic uint32_t rand32(void) 8570af302Sopenharmony_ci{ 9570af302Sopenharmony_ci seed = 6364136223846793005ULL*seed + 1; 10570af302Sopenharmony_ci return seed >> 32; 11570af302Sopenharmony_ci} 12570af302Sopenharmony_cistatic uint64_t rand64(void) 13570af302Sopenharmony_ci{ 14570af302Sopenharmony_ci uint64_t u = rand32(); 15570af302Sopenharmony_ci return u<<32 | rand32(); 16570af302Sopenharmony_ci} 17570af302Sopenharmony_cistatic double frand() 18570af302Sopenharmony_ci{ 19570af302Sopenharmony_ci return rand64() * 0x1p-64; 20570af302Sopenharmony_ci} 21570af302Sopenharmony_cistatic float frandf() 22570af302Sopenharmony_ci{ 23570af302Sopenharmony_ci return rand32() * 0x1p-32f; 24570af302Sopenharmony_ci} 25570af302Sopenharmony_cistatic long double frandl() 26570af302Sopenharmony_ci{ 27570af302Sopenharmony_ci return rand64() * 0x1p-64L 28570af302Sopenharmony_ci#if LDBL_MANT_DIG > 64 29570af302Sopenharmony_ci+ rand64() * 0x1p-128L 30570af302Sopenharmony_ci#endif 31570af302Sopenharmony_ci; 32570af302Sopenharmony_ci} 33570af302Sopenharmony_ci 34570af302Sopenharmony_civoid t_randseed(uint64_t s) 35570af302Sopenharmony_ci{ 36570af302Sopenharmony_ci seed = s; 37570af302Sopenharmony_ci} 38570af302Sopenharmony_ci 39570af302Sopenharmony_ci/* uniform random in [0,n), n > 0 must hold */ 40570af302Sopenharmony_ciuint64_t t_randn(uint64_t n) 41570af302Sopenharmony_ci{ 42570af302Sopenharmony_ci uint64_t r, m; 43570af302Sopenharmony_ci 44570af302Sopenharmony_ci /* m is the largest multiple of n */ 45570af302Sopenharmony_ci m = -1; 46570af302Sopenharmony_ci m -= m%n; 47570af302Sopenharmony_ci while ((r = rand64()) >= m); 48570af302Sopenharmony_ci return r%n; 49570af302Sopenharmony_ci} 50570af302Sopenharmony_ci 51570af302Sopenharmony_ci/* uniform on [a,b], a <= b must hold */ 52570af302Sopenharmony_ciuint64_t t_randint(uint64_t a, uint64_t b) 53570af302Sopenharmony_ci{ 54570af302Sopenharmony_ci uint64_t n = b - a + 1; 55570af302Sopenharmony_ci if (n) 56570af302Sopenharmony_ci return a + t_randn(n); 57570af302Sopenharmony_ci return rand64(); 58570af302Sopenharmony_ci} 59570af302Sopenharmony_ci 60570af302Sopenharmony_ci/* shuffle the elements of p and q until the elements in p are well shuffled */ 61570af302Sopenharmony_cistatic void shuffle2(uint64_t *p, uint64_t *q, size_t np, size_t nq) 62570af302Sopenharmony_ci{ 63570af302Sopenharmony_ci size_t r; 64570af302Sopenharmony_ci uint64_t t; 65570af302Sopenharmony_ci 66570af302Sopenharmony_ci while (np) { 67570af302Sopenharmony_ci r = t_randn(nq+np--); 68570af302Sopenharmony_ci t = p[np]; 69570af302Sopenharmony_ci if (r < nq) { 70570af302Sopenharmony_ci p[np] = q[r]; 71570af302Sopenharmony_ci q[r] = t; 72570af302Sopenharmony_ci } else { 73570af302Sopenharmony_ci p[np] = p[r-nq]; 74570af302Sopenharmony_ci p[r-nq] = t; 75570af302Sopenharmony_ci } 76570af302Sopenharmony_ci } 77570af302Sopenharmony_ci} 78570af302Sopenharmony_ci 79570af302Sopenharmony_ci/* shuffle the elements of p */ 80570af302Sopenharmony_civoid t_shuffle(uint64_t *p, size_t n) 81570af302Sopenharmony_ci{ 82570af302Sopenharmony_ci shuffle2(p,0,n,0); 83570af302Sopenharmony_ci} 84570af302Sopenharmony_ci 85570af302Sopenharmony_civoid t_randrange(uint64_t *p, size_t n) 86570af302Sopenharmony_ci{ 87570af302Sopenharmony_ci size_t i; 88570af302Sopenharmony_ci for (i = 0; i < n; i++) 89570af302Sopenharmony_ci p[i] = i; 90570af302Sopenharmony_ci t_shuffle(p, n); 91570af302Sopenharmony_ci} 92570af302Sopenharmony_ci 93570af302Sopenharmony_ci/* hash table insert, 0 means empty, v > 0 must hold, len is power-of-2 */ 94570af302Sopenharmony_cistatic int insert(uint64_t *tab, size_t len, uint64_t v) 95570af302Sopenharmony_ci{ 96570af302Sopenharmony_ci size_t i = v & (len-1); 97570af302Sopenharmony_ci size_t j = 1; 98570af302Sopenharmony_ci 99570af302Sopenharmony_ci while (tab[i]) { 100570af302Sopenharmony_ci if (tab[i] == v) 101570af302Sopenharmony_ci return -1; 102570af302Sopenharmony_ci i += j++; 103570af302Sopenharmony_ci i &= len-1; 104570af302Sopenharmony_ci } 105570af302Sopenharmony_ci tab[i] = v; 106570af302Sopenharmony_ci return 0; 107570af302Sopenharmony_ci} 108570af302Sopenharmony_ci 109570af302Sopenharmony_ci/* choose k unique numbers from [0,n), k <= n */ 110570af302Sopenharmony_ciint t_choose(uint64_t n, size_t k, uint64_t *p) 111570af302Sopenharmony_ci{ 112570af302Sopenharmony_ci uint64_t *tab; 113570af302Sopenharmony_ci size_t i, j, len; 114570af302Sopenharmony_ci 115570af302Sopenharmony_ci if (n < k) 116570af302Sopenharmony_ci return -1; 117570af302Sopenharmony_ci 118570af302Sopenharmony_ci if (n < 16) { 119570af302Sopenharmony_ci /* no alloc */ 120570af302Sopenharmony_ci while (k) 121570af302Sopenharmony_ci if (t_randn(n--) < k) 122570af302Sopenharmony_ci p[--k] = n; 123570af302Sopenharmony_ci return 0; 124570af302Sopenharmony_ci } 125570af302Sopenharmony_ci 126570af302Sopenharmony_ci if (k < 8) { 127570af302Sopenharmony_ci /* no alloc, n > 15 > 2*k */ 128570af302Sopenharmony_ci for (i = 0; i < k;) { 129570af302Sopenharmony_ci p[i] = t_randn(n); 130570af302Sopenharmony_ci for (j = 0; p[j] != p[i]; j++); 131570af302Sopenharmony_ci if (j == i) 132570af302Sopenharmony_ci i++; 133570af302Sopenharmony_ci } 134570af302Sopenharmony_ci return 0; 135570af302Sopenharmony_ci } 136570af302Sopenharmony_ci 137570af302Sopenharmony_ci // TODO: if k < n/k use k*log(k) solution without alloc 138570af302Sopenharmony_ci 139570af302Sopenharmony_ci if (n < 5*k && (n-k)*sizeof *tab < (size_t)-1) { 140570af302Sopenharmony_ci /* allocation is n-k < 4*k */ 141570af302Sopenharmony_ci tab = malloc((n-k) * sizeof *tab); 142570af302Sopenharmony_ci if (!tab) 143570af302Sopenharmony_ci return -1; 144570af302Sopenharmony_ci for (i = 0; i < k; i++) 145570af302Sopenharmony_ci p[i] = i; 146570af302Sopenharmony_ci for (; i < n; i++) 147570af302Sopenharmony_ci tab[i-k] = i; 148570af302Sopenharmony_ci if (k < n-k) 149570af302Sopenharmony_ci shuffle2(p, tab, k, n-k); 150570af302Sopenharmony_ci else 151570af302Sopenharmony_ci shuffle2(tab, p, n-k, k); 152570af302Sopenharmony_ci free(tab); 153570af302Sopenharmony_ci return 0; 154570af302Sopenharmony_ci } 155570af302Sopenharmony_ci 156570af302Sopenharmony_ci /* allocation is 2*k <= len < 4*k */ 157570af302Sopenharmony_ci for (len = 16; len < 2*k; len *= 2); 158570af302Sopenharmony_ci tab = calloc(len, sizeof *tab); 159570af302Sopenharmony_ci if (!tab) 160570af302Sopenharmony_ci return -1; 161570af302Sopenharmony_ci for (i = 0; i < k; i++) 162570af302Sopenharmony_ci while (insert(tab, len, t_randn(n)+1)); 163570af302Sopenharmony_ci for (i = 0; i < len; i++) 164570af302Sopenharmony_ci if (tab[i]) 165570af302Sopenharmony_ci *p++ = tab[i]-1; 166570af302Sopenharmony_ci free(tab); 167570af302Sopenharmony_ci return 0; 168570af302Sopenharmony_ci} 169570af302Sopenharmony_ci 170