/**
 * @file src/rand.c
 * @brief Define xorshift
 */

#include "rand.h"
#include "benchmarking.h"
#include "mathdef.h"
#include "testing.h"
#include <stdlib.h>
#include <time.h>

thread_local uint64_t state;

uint64_t xorsh() {
  state ^= state << 13;
  state ^= state >> 7;
  state ^= state << 17;
  return state;
}

double xorsh0to1() {
  return (double)xorsh() / (double)-1UL;
}

void sxorsh(uint64_t s) {
  state = s;
}

[[gnu::constructor(101)]] void initXorsh() {
  sxorsh((uint64_t)clock());
  _ = xorsh();
}

test (rand) {
  expect(true);

  test_filter("all,rand") {
    constexpr size_t n = 10'000;
    srand((unsigned)clock());

    unsigned rand_arr[n];
    unsigned xors_arr[n];
    double rand_av = 0;
    double xors_av = 0;
    for (size_t i = 0; i < n; i++) {
      rand_arr[i] = (unsigned _BitInt(31))rand();
      xors_arr[i] = (unsigned _BitInt(31))xorsh();
      rand_av += rand_arr[i] / n;
      xors_av += xors_arr[i] / n;
    }
    double rand_vari = 0;
    double xors_vari = 0;
    for (size_t i = 0; i < n; i++) {
      rand_vari += pow(rand_arr[i] - rand_av, 2) / n;
      xors_vari += pow(xors_arr[i] - xors_av, 2) / n;
    }
    puts("");
    printf("rand: av %lf vari %lf\n", rand_av, rand_vari);
    printf("xors: av %lf vari %lf\n", xors_av, xors_vari);
  }
}

bench (rand) { // 0.0173 ms
  _ = rand();
}

bench (xorsh) { // 0.0045 ms
  _ = xorsh();
}

bench_cycle(rand) {
  _ = rand();
}

bench_cycle(xors) {
  _ = xorsh();
}