// Random generator using jrand48 as bitstream. (3.01)
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <stdio.h>
#include <time.h>
_Static_assert((-1 & 3) == 3, "Not 2's complement");
_Static_assert(UINT_MAX == (unsigned int) INT_MAX - INT_MIN, "Bad integer");
#define BITS(x) (sizeof(x) * CHAR_BIT)
int bitlength(unsigned long x)
{
return x ? BITS(x) - __builtin_clzl(x) : 0;
}
// Private.
static _Thread_local unsigned short generator_state[3] = {
0x330E, 0xABCD, 0x1234};
static uint_fast32_t generator_next(void)
{
return jrand48(generator_state) + (UINT32_C(1) << 31);
}
static uint_fast32_t takebits(uint_fast32_t x, int available, int take)
{
return (x >> (available - take)) & (UINT32_C(-1) >> (BITS(x) - take));
}
// Public.
void randseed(uint_least64_t seed)
{
generator_state[0] = seed;
generator_state[1] = seed >> 16;
generator_state[2] = seed >> 32;
}
uint_least64_t randbits(int n)
{
static _Thread_local uint_fast32_t reservoir = 0;
static _Thread_local int available = 0;
uint_fast64_t r = 0;
while (n > 0)
{
if (available == 0)
{
reservoir = generator_next();
available = 32;
}
int take = (available < n) ? available : n;
r = (r << take) | takebits(reservoir, available, take);
available -= take;
n -= take;
}
return r;
}
uint_least32_t randuint(uint_least32_t max)
{
max &= UINT32_C(0xFFFFFFFF);
if (max == 0)
return 0;
int bits = bitlength(max);
uint_fast32_t res_max = UINT32_C(-1) >> (BITS(max) - bits);
uint_fast32_t res = randbits(bits);
if (max == res_max)
return res;
uint_fast32_t mod = max + 1;
uint_fast32_t lim = res_max + 1;
uint_fast32_t min = (lim - mod) % mod;
while (res < min)
res = randbits(bits);
res %= mod;
return res;
}
double randreal(void)
{
double r = randbits(DBL_MANT_DIG) / exp2(DBL_MANT_DIG);
return r;
}
_Bool randbool(double p)
{
return randreal() < p;
}
// Test.
int uniform_int_distribution_uint(int a, int b)
{
return randuint((unsigned int) b - a) + a;
}
int uniform_int_distribution_real(int a, int b)
{
return randreal() * (1.0 + b - a) + a;
}
int bernoulli_distribution_50_50(int a, int b)
{
return randbool(0.5);
}
unsigned long random_device()
{
unsigned long r;
size_t n = 0;
FILE
*fp
= fopen("/dev/urandom", "r"); if (fp)
{
n
= fread(&r
, sizeof r
, 1, fp
); }
if (n == 1)
return r;
}
double chi_square(int n, int k, int (*f)(int, int))
{
int *h
= calloc(k
, sizeof *h
); for (int j = 0; j < n; j++)
{
int i = f(0, k-1);
h[i] += 1;
}
double expect = (double) n / k;
double x2 = 0;
for (int i = 0; i < k; i++)
x2
+= pow(h
[i
] - expect
, 2) / expect
; return x2;
}
void test(int m, int n, int df, double x2, int (*f)(int, int),
const char *header)
{
for (int i = 0; i < m; i++)
{
double r = chi_square(n, df, f);
printf(" significant: %-5s [%6.2f][%6.2f]\n", r >= x2 ? "true" : "false", r, x2);
}
}
int main(void)
{
unsigned long seed = random_device();
randseed(seed);
int m = 5;
int n = 10000;
// PV=0.05 for all tests.
test(m, n, 100, 124.34, uniform_int_distribution_uint,
"uniform_int_distribution_uint");
test(m, n, 100, 124.34, uniform_int_distribution_real,
"uniform_int_distribution_real");
test(m, n, 2, 5.99, bernoulli_distribution_50_50,
"bernoulli_distribution_50_50");
return 0;
}
Ly8gUmFuZG9tIGdlbmVyYXRvciB1c2luZyBqcmFuZDQ4IGFzIGJpdHN0cmVhbS4gKDMuMDEpCgojaW5jbHVkZSA8c3RkbGliLmg+CiNpbmNsdWRlIDxzdGRpbnQuaD4KI2luY2x1ZGUgPGxpbWl0cy5oPgojaW5jbHVkZSA8YXNzZXJ0Lmg+CiNpbmNsdWRlIDxtYXRoLmg+CiNpbmNsdWRlIDxmbG9hdC5oPgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHRpbWUuaD4KCl9TdGF0aWNfYXNzZXJ0KCgtMSAmIDMpID09IDMsICJOb3QgMidzIGNvbXBsZW1lbnQiKTsKX1N0YXRpY19hc3NlcnQoVUlOVF9NQVggPT0gKHVuc2lnbmVkIGludCkgSU5UX01BWCAtIElOVF9NSU4sICJCYWQgaW50ZWdlciIpOwoKI2RlZmluZSBCSVRTKHgpIChzaXplb2YoeCkgKiBDSEFSX0JJVCkKCmludCBiaXRsZW5ndGgodW5zaWduZWQgbG9uZyB4KQp7CiAgICByZXR1cm4geCA/IEJJVFMoeCkgLSBfX2J1aWx0aW5fY2x6bCh4KSA6IDA7Cn0KCi8vIFByaXZhdGUuCgpzdGF0aWMgX1RocmVhZF9sb2NhbCB1bnNpZ25lZCBzaG9ydCBnZW5lcmF0b3Jfc3RhdGVbM10gPSB7CiAgICAweDMzMEUsIDB4QUJDRCwgMHgxMjM0fTsKCnN0YXRpYyB1aW50X2Zhc3QzMl90IGdlbmVyYXRvcl9uZXh0KHZvaWQpCnsKICAgIHJldHVybiBqcmFuZDQ4KGdlbmVyYXRvcl9zdGF0ZSkgKyAoVUlOVDMyX0MoMSkgPDwgMzEpOwp9CgpzdGF0aWMgdWludF9mYXN0MzJfdCB0YWtlYml0cyh1aW50X2Zhc3QzMl90IHgsIGludCBhdmFpbGFibGUsIGludCB0YWtlKQp7CiAgICBhc3NlcnQodGFrZSA+PSAxKTsKICAgIGFzc2VydCh0YWtlIDw9IGF2YWlsYWJsZSk7CiAgICByZXR1cm4gKHggPj4gKGF2YWlsYWJsZSAtIHRha2UpKSAmIChVSU5UMzJfQygtMSkgPj4gKEJJVFMoeCkgLSB0YWtlKSk7Cn0KCi8vIFB1YmxpYy4KCnZvaWQgcmFuZHNlZWQodWludF9sZWFzdDY0X3Qgc2VlZCkKewogICAgZ2VuZXJhdG9yX3N0YXRlWzBdID0gc2VlZDsKICAgIGdlbmVyYXRvcl9zdGF0ZVsxXSA9IHNlZWQgPj4gMTY7CiAgICBnZW5lcmF0b3Jfc3RhdGVbMl0gPSBzZWVkID4+IDMyOwp9Cgp1aW50X2xlYXN0NjRfdCByYW5kYml0cyhpbnQgbikKewogICAgYXNzZXJ0KG4gPD0gNjQpOwogICAgc3RhdGljIF9UaHJlYWRfbG9jYWwgdWludF9mYXN0MzJfdCByZXNlcnZvaXIgPSAwOwogICAgc3RhdGljIF9UaHJlYWRfbG9jYWwgaW50IGF2YWlsYWJsZSA9IDA7CgogICAgdWludF9mYXN0NjRfdCByID0gMDsKCiAgICB3aGlsZSAobiA+IDApCiAgICB7CiAgICAgICAgaWYgKGF2YWlsYWJsZSA9PSAwKQogICAgICAgIHsKICAgICAgICAgICAgcmVzZXJ2b2lyID0gZ2VuZXJhdG9yX25leHQoKTsKICAgICAgICAgICAgYXZhaWxhYmxlID0gMzI7CiAgICAgICAgfQoKICAgICAgICBpbnQgdGFrZSA9IChhdmFpbGFibGUgPCBuKSA/IGF2YWlsYWJsZSA6IG47CiAgICAgICAgciA9IChyIDw8IHRha2UpIHwgdGFrZWJpdHMocmVzZXJ2b2lyLCBhdmFpbGFibGUsIHRha2UpOwogICAgICAgIGF2YWlsYWJsZSAtPSB0YWtlOwogICAgICAgIG4gLT0gdGFrZTsKICAgIH0KICAgIHJldHVybiByOwp9Cgp1aW50X2xlYXN0MzJfdCByYW5kdWludCh1aW50X2xlYXN0MzJfdCBtYXgpCnsKICAgIG1heCAmPSBVSU5UMzJfQygweEZGRkZGRkZGKTsKCiAgICBpZiAobWF4ID09IDApCiAgICAgICAgcmV0dXJuIDA7CgogICAgaW50IGJpdHMgPSBiaXRsZW5ndGgobWF4KTsKICAgIHVpbnRfZmFzdDMyX3QgcmVzX21heCA9IFVJTlQzMl9DKC0xKSA+PiAoQklUUyhtYXgpIC0gYml0cyk7CiAgICB1aW50X2Zhc3QzMl90IHJlcyA9IHJhbmRiaXRzKGJpdHMpOwoKICAgIGlmIChtYXggPT0gcmVzX21heCkKICAgICAgICByZXR1cm4gcmVzOwoKICAgIHVpbnRfZmFzdDMyX3QgbW9kID0gbWF4ICsgMTsKICAgIHVpbnRfZmFzdDMyX3QgbGltID0gcmVzX21heCArIDE7CiAgICB1aW50X2Zhc3QzMl90IG1pbiA9IChsaW0gLSBtb2QpICUgbW9kOwoKICAgIHdoaWxlIChyZXMgPCBtaW4pCiAgICAgICAgcmVzID0gcmFuZGJpdHMoYml0cyk7CiAgICByZXMgJT0gbW9kOwogICAgcmV0dXJuIHJlczsKfQoKZG91YmxlIHJhbmRyZWFsKHZvaWQpCnsKICAgIGRvdWJsZSByID0gcmFuZGJpdHMoREJMX01BTlRfRElHKSAvIGV4cDIoREJMX01BTlRfRElHKTsKICAgIGFzc2VydChyIDwgMS4wKTsKICAgIHJldHVybiByOwp9CgpfQm9vbCByYW5kYm9vbChkb3VibGUgcCkKewogICAgYXNzZXJ0KDAuMCA8PSBwICYmIHAgPD0gMS4wKTsKICAgIHJldHVybiByYW5kcmVhbCgpIDwgcDsKfQoKLy8gVGVzdC4KCmludCB1bmlmb3JtX2ludF9kaXN0cmlidXRpb25fdWludChpbnQgYSwgaW50IGIpCnsKICAgIGFzc2VydChhIDw9IGIpOwogICAgcmV0dXJuIHJhbmR1aW50KCh1bnNpZ25lZCBpbnQpIGIgLSBhKSArIGE7Cn0KCmludCB1bmlmb3JtX2ludF9kaXN0cmlidXRpb25fcmVhbChpbnQgYSwgaW50IGIpCnsKICAgIGFzc2VydChhIDw9IGIpOwogICAgcmV0dXJuIHJhbmRyZWFsKCkgKiAoMS4wICsgYiAtIGEpICsgYTsKfQoKaW50IGJlcm5vdWxsaV9kaXN0cmlidXRpb25fNTBfNTAoaW50IGEsIGludCBiKQp7CiAgICBhc3NlcnQoYSA9PSAwICYmIGIgPT0gMSk7CiAgICByZXR1cm4gcmFuZGJvb2woMC41KTsKfQoKdW5zaWduZWQgbG9uZyByYW5kb21fZGV2aWNlKCkKewogICAgdW5zaWduZWQgbG9uZyByOwogICAgc2l6ZV90IG4gPSAwOwogICAgRklMRSAqZnAgPSBmb3BlbigiL2Rldi91cmFuZG9tIiwgInIiKTsKICAgIGlmIChmcCkKICAgIHsKICAgICAgICBuID0gZnJlYWQoJnIsIHNpemVvZiByLCAxLCBmcCk7CiAgICAgICAgZmNsb3NlKGZwKTsKICAgIH0KICAgIGlmIChuID09IDEpCiAgICAgICAgcmV0dXJuIHI7CiAgICByZXR1cm4gdGltZSgwKTsKfQoKZG91YmxlIGNoaV9zcXVhcmUoaW50IG4sIGludCBrLCBpbnQgKCpmKShpbnQsIGludCkpCnsKICAgIGludCAqaCA9IGNhbGxvYyhrLCBzaXplb2YgKmgpOwogICAgYXNzZXJ0KGggIT0gMCB8fCBrID09IDApOwogICAgZm9yIChpbnQgaiA9IDA7IGogPCBuOyBqKyspCiAgICB7CiAgICAgICAgaW50IGkgPSBmKDAsIGstMSk7CiAgICAgICAgYXNzZXJ0KDAgPD0gaSAmJiBpIDwgayk7CiAgICAgICAgaFtpXSArPSAxOwogICAgfQogICAgZG91YmxlIGV4cGVjdCA9IChkb3VibGUpIG4gLyBrOwogICAgZG91YmxlIHgyID0gMDsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgazsgaSsrKQogICAgICAgIHgyICs9IHBvdyhoW2ldIC0gZXhwZWN0LCAyKSAvIGV4cGVjdDsKICAgIGZyZWUoaCk7CiAgICByZXR1cm4geDI7Cn0KCnZvaWQgdGVzdChpbnQgbSwgaW50IG4sIGludCBkZiwgZG91YmxlIHgyLCBpbnQgKCpmKShpbnQsIGludCksCiAgICAgICAgICBjb25zdCBjaGFyICpoZWFkZXIpCnsKICAgIHB1dHMoaGVhZGVyKTsKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgbTsgaSsrKQogICAgewogICAgICAgIGRvdWJsZSByID0gY2hpX3NxdWFyZShuLCBkZiwgZik7CiAgICAgICAgcHJpbnRmKCIgc2lnbmlmaWNhbnQ6ICUtNXMgWyU2LjJmXVslNi4yZl1cbiIsCiAgICAgICAgICAgICAgIHIgPj0geDIgPyAidHJ1ZSIgOiAiZmFsc2UiLCByLCB4Mik7CiAgICB9Cn0KCmludCBtYWluKHZvaWQpCnsKICAgIHVuc2lnbmVkIGxvbmcgc2VlZCA9IHJhbmRvbV9kZXZpY2UoKTsKICAgIHByaW50Zigic2VlZDogJWx1XG4iLCBzZWVkKTsKICAgIHJhbmRzZWVkKHNlZWQpOwoKICAgIGludCBtID0gNTsKICAgIGludCBuID0gMTAwMDA7CgogICAgLy8gUFY9MC4wNSBmb3IgYWxsIHRlc3RzLgoKICAgIHRlc3QobSwgbiwgMTAwLCAxMjQuMzQsIHVuaWZvcm1faW50X2Rpc3RyaWJ1dGlvbl91aW50LAogICAgICAgICAidW5pZm9ybV9pbnRfZGlzdHJpYnV0aW9uX3VpbnQiKTsKICAgIHRlc3QobSwgbiwgMTAwLCAxMjQuMzQsIHVuaWZvcm1faW50X2Rpc3RyaWJ1dGlvbl9yZWFsLAogICAgICAgICAidW5pZm9ybV9pbnRfZGlzdHJpYnV0aW9uX3JlYWwiKTsKICAgIHRlc3QobSwgbiwgMiwgNS45OSwgYmVybm91bGxpX2Rpc3RyaWJ1dGlvbl81MF81MCwKICAgICAgICAgImJlcm5vdWxsaV9kaXN0cmlidXRpb25fNTBfNTAiKTsKICAgIHJldHVybiAwOwp9