#include <iostream>
#include <random>
#include <chrono>
using namespace std::chrono;

int main()
{
    // variables
	size_t start_time = 0, end_time = 0, for_time = 0; // speed record
	unsigned int N = 100000;
	double *a = new double [N]; // array of random numbers
	unsigned int i=0;
	std::normal_distribution<double> dist(0,1); // N(0,1) distribution

	printf("1.Test duration_cast<precision>(duration_object).count() method:\n");
	size_t t64 = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	printf("  time now in dec ns: %u (uint64, directly obtained)\n", t64);
	printf("           in hex   : %16llx\n\n", t64);

    printf("2.make sure uint64 -> uint32 discards higher bits(suitable for seeding):\n");
	unsigned long t32 = static_cast<unsigned long>(t64);
	printf("  time now in hex ns: %16x (truncated to uint32)\n\n", t32);

	printf("3.generating %u N(0,1) random numbers using different engines...\n", N);

	// Time cost of for-loop body
	start_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	for(i=0; i<N; i++){}
	end_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	for_time = end_time - start_time;
	printf("%16u ns used on for-loop body\n", for_time);

	// mt19937 engine
	start_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	std::mt19937 mt(static_cast<unsigned long>(duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count()));
	for(i=0; i<N; i++)
		a[i] = dist(mt);
	end_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	printf("%16u ns for mt19937\n", (end_time-start_time-for_time)) ;

	// mt19937_64 engine
	start_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	std::mt19937_64 mt64(static_cast<unsigned long>(duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count()));
	for(i=0; i<N; i++)
		a[i] = dist(mt64);
	end_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	printf("%16u ns for mt19937_64\n", (end_time-start_time-for_time)) ;

	// minstd_rand engine
	start_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	std::minstd_rand  min_rnd(static_cast<unsigned long>(duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count()));
	for(i=0; i<N; i++)
		a[i] = dist(min_rnd);
	end_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	printf("%16u ns for minstd_rand\n", (end_time-start_time-for_time)) ;

	// default_random_engine
	start_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	std::default_random_engine def_rnd(static_cast<unsigned long>(duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count()));
	for(i=0; i<N; i++)
		a[i] = dist(def_rnd);
	end_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	printf("%16u ns for default_random_engine\n", (end_time-start_time-for_time)) ;

	// random_device (hardware generator)
	start_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	std::random_device rd;
	for(i=0; i<N; i++)
		a[i] = dist(rd);
	end_time = duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
	printf("%16u ns for random_device\n", (end_time-start_time-for_time)) ;

	delete [] a;
	system("PAUSE");
	return 0;
}