#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>

uint32_t lcg_rand(uint32_t *a)
{
	*(uint32_t *)a = (uint64_t)*(uint32_t *)a * 279470273 % 4294967291;
	return( *(uint32_t *)a );
}

uint32_t lrand(uint64_t *s){
    // initial value of s must be 2 or higher
    uint64_t hi = *(uint64_t *)s / 41943011;
    uint64_t lo = *(uint64_t *)s % 41943011;
    //uint64_t tmp = *(uint64_t *)s * lo;
    *(uint64_t *)s = *(uint64_t *)s * lo - 2147483647 * hi;

    //if(*(uint64_t *)s < 0) *(uint64_t *)s += 0x7fffffffffffffff;
    return (*(uint64_t *)s & 0xFFFFFFFF00000000) >> 32;
}

uint16_t lrand2(uint32_t *s){
	uint32_t hi = *(uint32_t *)s / 49301;
	uint32_t lo = *(uint32_t *)s % 49301;
	*(uint32_t *)s = *(uint32_t *)s * lo - 655535 * hi;
	return (*(uint32_t *)s & 0xFFFF0000) >> 16;
}
/*
uint32_t xor128(void) {
  static uint32_t x = 123456789;
  static uint32_t y = 362436069;
  static uint32_t z = 521288629;
  static uint32_t w = 88675123;
  uint32_t t;

  t = x ^ (x << 11);
  x = y; y = z; z = w;
  return w = w ^ (w >> 19) ^ (t ^ (t >> 8));
}
*/
struct Rand_S{
	uint16_t x;
	uint16_t y;
	//uint16_t z;
	//uint16_t w;
};

uint16_t xor128(struct Rand_S *s) {
  //static uint32_t x = 123456789;
  //static uint32_t y = 362436069;
  //static uint32_t z = 521288629;
  //static uint32_t w = 88675123;
  uint16_t t;

	t = s->x ^ (s->x << 5);
	s->x = s->y; 
	//s->y = s->z; 
	//s->z = s->w;


  return s->y = s->y ^ (s->y >> 9) ^ (t ^ (t >> 4));
}


int main(int argc, char **argv){
	struct timeval starttime, endtime, cur;
	uint32_t a;
	uint32_t b = 103;
	uint32_t c;
	uint64_t d = 103;
	double time1;
	uint32_t *e = malloc(sizeof(uint32_t)*32000000); //1GB
	uint64_t counts[10];
	(void)memset(counts, '\0', sizeof(uint64_t)*10);
	uint16_t f;
	struct Rand_S Seed;
	//printf("here 1\n");
	gettimeofday(&starttime, NULL);
	Seed.x = (uint16_t)starttime.tv_usec-4;
	Seed.y = (uint16_t)starttime.tv_usec-3;
	//Seed.z = (uint16_t)starttime.tv_usec-2;
	//Seed.w = (uint16_t)starttime.tv_usec;
/*
	for(a=1; a<4096; a++){
		//gettimeofday(&starttime, NULL);
		//b = (unsigned int)starttime.tv_usec;
		e[a] = xor128(&Seed) % 10;
		//e[a] = lcg_rand(&b) % 10;
		//printf("%u\n", e[a]);
	}
	

	for(a=0; a<4096; a++){
		for(d=0; d<10; d++){
			if(e[a] == d)
				counts[d]++;
		}
	}
	for(d=0; d<10; d++){
		printf("%.04lf%%\n", (double)counts[d]/4096*100);
	}

*/
//return 0;
  //  gettimeofday(&starttime, NULL);
   // b = (uint32_t)starttime.tv_usec;
	//d = (uint64_t)starttime.tv_usec;
	gettimeofday(&starttime, NULL);
	for(a=0; a<32000000; a++){
		//c = lcg_rand(&b);
		e[a] = xor128(&Seed) % 10;
	}
	gettimeofday(&endtime, NULL);
	time1 = ((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
    for(a=0; a<32000000; a++){
        for(c=0; c<10; c++){
            if(e[a] == c)
                counts[c]++;
        }
    }
    for(c=0; c<10; c++){
        printf("%lu\n", counts[c]);
    }

	printf("xor128 %lf\n", time1);
//	return 0;
	(void)memset(counts, '\0', sizeof(uint64_t)*10);
	gettimeofday(&starttime, NULL);
	for(a=0; a<32000000; a++){
		e[a] = lrand(&d) % 10;
	}
	gettimeofday(&endtime, NULL);
	time1 = ((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
    for(a=0; a<32000000; a++){
        for(c=0; c<10; c++){
            if(e[a] == c)
                counts[c]++;
        }
    }
    for(c=0; c<10; c++){
        printf("%lu\n", counts[c]);
    }

	printf("lrand %lf\n", time1);

	free(e);
	return 0;
}