#include <v_lib.h>

#define	SOME_VALUE	0.1
#define	X_LIMIT		((vec_t)1000)

static vec_t one_by_sqrt_2pi;

void V_CALL deriv(void_p custom,vec_p dxdy,vec_t x,vec_p y)
{
	dxdy[0] = one_by_sqrt_2pi * exp(- x * x / 2) ;
}

__int64 get_cpu_clock(void)
{
	u32_t clock_hi, clock_lo;
	__asm {
		rdtsc
		mov clock_lo, eax
		mov clock_hi, edx
	}
	return (__int64)clock_lo + ((__int64)clock_hi << 32);
}

__int64 cpu_freq;

void calibrate_tsc_timer(void)
{
	__int64 tsc_new;
	printf("Calibrating TSC timer...");
	do
	{
		cpu_freq = get_cpu_clock();
		timeDelay(1000);
		tsc_new = get_cpu_clock();
	} while(tsc_new < cpu_freq);
	cpu_freq = tsc_new - cpu_freq;
	printf(" Ok (~%u MHz CPU)\n", (u32_t)(cpu_freq / 1000000));
}

vec_t tsc_millidiff(__int64 tsc_start)
{
	__int64 tsc_new = get_cpu_clock();
	if(tsc_new < tsc_start)
		tsc_new -= 0xFFFFFFFFFFFFFFFF; /* overflow */
	tsc_start = tsc_new - tsc_start;
	return (vec_t)tsc_start * 1000 / cpu_freq; 
}

int main()
{
	__int64 tic;
	vec_t y, millidiff;
	vhandle_t solver;
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	calibrate_tsc_timer();
	one_by_sqrt_2pi = 1 / sqrt(M_2PI);
	solver = odeCreateSolver(1,deriv,true);
	/*
	 * We can't integrate from '-infinity' since the integral is zero
	 * here and, thus, its impossible to restore the Gaussian curve.
	 * The Gaussian is even function. We can integrate from _zero_,
	 * passing arbitrary non-zero value as Fi(0); all we have to do
	 * later is to _subtract_ this value and double the result.
 	 */
	y = SOME_VALUE;
	tic = get_cpu_clock();
	odeIntegrate(solver,&y,0,X_LIMIT,1e-10,1e-6,1e-10,NULL);
	millidiff = tsc_millidiff(tic);
	odeDestroySolver(solver);
	
	conPrintf("1/sqrt(2*Pi) * int(exp(- x * x / 2),x=-%g..%g) = %1.12g"
		" (%.3g milliseconds).\n",
		X_LIMIT,X_LIMIT,(y - SOME_VALUE) * 2,millidiff);

	memPrintStats();
	return 0;
}
