#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <iostream>

using namespace std;

#define N_PRIME 41

typedef unsigned long long value_t;
typedef long long svalue_t;

value_t seed = 0xCAFABABEFFFFFFFF;
const value_t prime_array[N_PRIME] = {
   7561UL,
   7573UL,
	7577UL,
   7583UL,
	7589UL,
	7591UL,
	7603UL,
	7607UL,
	7621UL,
	7639UL,
	7643UL,
	7649UL,
	7669UL,
	7673UL,
	7681UL,
	7687UL,
	7691UL,
	7699UL,
	7703UL,
	7717UL,
	7723UL,
   7727UL,
   7741UL,
   7753UL,
   7757UL,
	7759UL,
	7789UL,
	7793UL,
	7817UL,
	7823UL,
	7829UL,
   7841UL,
	7853UL,
	7867UL,
	7873UL,
	7877UL,
	7879UL,
	7883UL,
	7901UL,
	7907UL,
	7919UL,
};

svalue_t my_abs(svalue_t x);
value_t pow_two(value_t x);
void my_srand(value_t sd);
value_t spin64(value_t rnd); 
value_t rand0();
value_t my_rand();

svalue_t my_abs(svalue_t x)
{
   svalue_t ret = x;
   if(x < 0) {
      ret *= -1L;
   }
   return ret;
}

value_t pow_two(value_t x)
{
   value_t ret = 1L;
   value_t i;
   for(i = 0; i < x; i++) 
      ret *= 2L;
   return ret;
}

void my_srand(value_t sd)
{
   seed = sd;
   my_rand();
   my_rand();
   my_rand();
   my_rand();
   my_rand();
}

value_t spin64(value_t rnd) 
{
   value_t end = rnd & pow_two(63UL);
   rnd <<= 1UL;
   if(end) {
      rnd |= 1UL;
   }
   return rnd;
}

value_t rand0()
{
   value_t rnd = seed;
   unsigned char* ptr1;
   unsigned char* ptr2;
   unsigned short* p1;
   unsigned short* p2;
   value_t j;
   value_t n = 8;
   value_t i;
   value_t k;
   double d;

   ptr1 = (unsigned char*)&seed;
   ptr2 = (unsigned char*)&rnd;
   p1 = (unsigned short*)&seed;
   p2 = (unsigned short*)&rnd;

   for(k = 1; k <= 11; k++) {
      for(j = 1; j <= 3; j++) {
         for(i = 1; i <= 16; i++) {
            switch(((value_t)ptr1[ptr2[((i+j*100)^seed)%n]%n] + (value_t)ptr2[ptr1[((i+k+55)|rnd)%n]%n])%16) {
            case 0:
            ptr1[ptr2[((i+j+k+prime_array[seed%N_PRIME])|seed)%n]%n] &= ptr2[ptr1[((33*i+j+k+prime_array[rnd%N_PRIME])&rnd)%n]%n];
            case 1:
            ptr1[ptr2[(seed|i)%n]%n] |= ptr2[ptr1[((100+i+k^j)^rnd)%n]%n];
            case 2:
            ptr2[ptr1[((i+k+55*prime_array[rnd%N_PRIME])^rnd)%n]%n] ^= ptr1[ptr2[(i^seed)%n]%n];
            case 3:
            ptr1[ptr2[(j|k|i|seed)%n]%n] &= ptr2[ptr1[((i+k*1001)|rnd)%n]%n];
            case 4:
            ptr2[ptr1[((i+j+k*1000)^rnd)%n]%n] |= ~ptr1[ptr2[(i^seed)%n]%n];
            case 5:
            ptr1[ptr2[(i|seed)%n]%n] ^= ~ptr2[ptr1[((3*i+k+prime_array[rnd%N_PRIME])^rnd)%n]%n];
            case 6:
            ptr2[ptr1[((i^k)^rnd)%n]%n] &= ~ptr1[ptr2[((i+j+5)|seed)%n]%n];
            case 7:
            ptr1[ptr2[((30+i+k|j)|seed)%n]%n] |= ptr2[(((value_t)(~ptr1[ptr2[((i+k+99)^seed)%n]%n])) + ((value_t)(~ptr2[ptr1[((i+j+k*9987)|rnd)%n]%n])))%n];
            case 8:
            ptr1[p2[((i*25)|seed)%4]%n] &= ptr2[p1[((i+j+k*100)&rnd)%4]%n];
            case 9:
            ptr1[p2[(seed^((100*i+k+j)^prime_array[seed%N_PRIME]))%4]%n] |= ptr2[p1[(i^rnd)%4]%n];
            case 10:
            ptr2[p1[(i^rnd)%4]%n] ^= ptr1[p2[((i+j+k*101)^seed)%4]%n];
            case 12:
            ptr1[p2[(((i^k)|j)|seed)%4]%n] &= ptr2[p1[(i|rnd)%4]%n];
            case 13:
            ptr2[p1[((i|k+j+11*prime_array[rnd%N_PRIME])^rnd)%4]%n] |= ~ptr1[p2[(i^seed)%4]%n];
            case 14:
            ptr1[p2[((i+j*1101)|seed)%4]%n] ^= ~ptr2[p1[((i+k+9)^rnd)%4]%n];
            case 15:
            ptr2[p1[((10*i+k+180)^rnd)%4]%n] &= ~ptr1[p2[((i+j+42)|seed)%4]%n];
            }
            rnd = spin64(rnd);
            seed = spin64(seed);
         }
      }
   }

   switch(rnd % 5) {
   case 0:
   seed = rnd^(~seed);
   break;
   case 1:
   seed = (~(rnd^seed));
   break;
   case 2:
   seed = (~(rnd|seed));
   break;
   case 3:
   seed = (~(rnd&seed));
   break;
   case 4:
   seed = ~rnd;
   break;
   }

   seed = spin64(seed);
   
   return rnd;
}

value_t my_rand()
{
   value_t temp;
   temp = rand0();
   return temp;
}

int
main(int argc, char** argv)
{
   value_t r;
   int count = 10;
   if(argc == 2) {
      count = atoi(argv[1]);
   }
   my_srand(GetTickCount64());
   while(count) {
      r = my_rand();
      cout << r << endl;
      count--;
   }
   return 0;
}

