#include	<stdio.h>
#include	<math.h>
#include	<time.h>
#include	<conio.h>

unsigned sqrt_fpu1(long l)
{
	if (l == 0)
		return 0;
	double f_rslt = sqrt(l);
	unsigned rslt = (int)f_rslt;
	if (!(f_rslt - rslt < .5))
		rslt ++;
	return rslt;
}

unsigned sqrt_cpu1(long l)
{
	long temp;
    unsigned div, rslt = l;
	if (l <= 0)
		return 0;
	else if (l & 0xFFFF0000L)
		if (l & 0xFF000000L)
           	div = 0x3FFF;
        else
           	div = 0x3FF;
    else
    	if (l & 0x0FF00L)
           	div = 0x3F;
        else
       		div = (l > 4) ? 0x7 : l;
	while (1)
	{
		temp = l / div + div;
		div = temp >> 1;
		div += temp & 1;
		if (rslt > div)
			rslt = div;
		else
		{
        	if (l / rslt == rslt - 1 && l % rslt == 0)
	  			rslt--;
			break;
		}
	}
	return (unsigned)rslt;
}

unsigned sqrt_cpu2(long l)
{
	if (l <= 0)
		return 0;
	long rslt = l, div = l;
	while (1)
	{
		div = (l / div + div) / 2;
		if (rslt > div)
			rslt = div;
		else
			break;
	}
	return (unsigned)rslt;
}

unsigned sqrt_cpu3(long l)
{
	unsigned div = 1;
    unsigned rslt = 0;
	while (l > 0)
	{
		l-= div, div += 2;
		rslt += l < 0 ? 0 : 1;
	}
    return rslt;
}

unsigned sqrt_cpu4(long l)
{
	unsigned div = 1, rslt = 0;
	while (l > 0)
	{
		l-= div, div += 2;
		rslt += l < 0 ? 0 : 1;
	}
    if (l != 0)
    	rslt++;
	return rslt;
}

#define	steps	1000
#define	range1	1000L
#define	range2	10000L
#define	range3	100000L
#define	count	2000

double times[3][3];

void CalcTime()
{
	long l;
	int i;
	time_t first, second;
	printf("testing range1=[%lu..%lu]...\n", 0L, range1);
	printf("fpu1...\n");
	first = time(NULL);

	for (i = 0; i < count; i++)
	for (l = 0l; l < range1; l += range1 / steps)
		sqrt_fpu1(l);
	second = time(NULL);
	times[0][0] = difftime(second, first);

	printf("cpu1...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = 0l; l < range1; l += range1 / steps)
		sqrt_cpu1(l);
	second = time(NULL);
	times[0][1] = difftime(second, first);

	printf("cpu2...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = 0l; l < range1; l += range1 / steps)
		sqrt_cpu2(l);
	second = time(NULL);
	times[0][2] = difftime(second, first);

	printf("testing range2=[%lu..%lu]...\n", range1, range2);
	printf("fpu1...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = range1; l < range2; l += (range2 - range1) / steps)
		sqrt_fpu1(l);
	second = time(NULL);
	times[1][0] = difftime(second, first);

	printf("cpu1...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = range1; l < range2; l += (range2 - range1) / steps)
		sqrt_cpu1(l);
	second = time(NULL);
	times[1][1] = difftime(second, first);

	printf("cpu2...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = range1; l < range2; l += (range2 - range1) / steps)
		sqrt_cpu2(l);
	second = time(NULL);
	times[1][2] = difftime(second, first);


	printf("testing range3=[%lu..%lu]...\n", range2, range3);
	printf("fpu1...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = range2; l < range3; l += (range3 - range2) / steps)
		sqrt_fpu1(l);
	second = time(NULL);
	times[2][0] = difftime(second, first);


	printf("cpu1...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = range2; l < range3; l += (range3 - range2) / steps)
		sqrt_cpu1(l);
	second = time(NULL);
	times[2][1] = difftime(second, first);


	printf("cpu2...\n");
	first = time(NULL);
	for (i = 0; i < count; i++)
	for (l = range2; l < range3; l += (range3 - range2) / steps)
		sqrt_cpu2(l);
	second = time(NULL);
	times[2][2] = difftime(second, first);

	printf("Done.\n");
	printf("range\t\t fpu1\t cpu1\t cpu2\n");
	printf(
		"%lu\t\t%5.3f\t%5.3f\t%5.3f\n",
		range1,
		times[0][0],
		times[0][1],
		times[0][2]
	);
	printf(
		"%lu\t\t%5.3f\t%5.3f\t%5.3f\n",
		range2,
		times[1][0],
		times[1][1],
		times[1][2]
	);
	printf(
		"%lu\t\t%5.3f\t%5.3f\t%5.3f\n",
		range3,
		times[2][0],
		times[2][1],
		times[2][2]
	);
}

typedef unsigned (*sqrt_func)(long L);

void ViewDifferents(long rang1, long rang2, unsigned step, sqrt_func fpsqrt)
{
	unsigned long l;
    unsigned rf, ri;
	printf("testing with range[%lu..%lu]\n", rang1, rang2);
	for (l = rang1; l < rang2; l += (rang2 - rang1) / step)
	{
    	rf = sqrt_fpu1(l);
        ri = (*fpsqrt)(l);
		if (rf != ri)
			printf("sqrt(%lu) %u %u %6.2f\n", l, rf, ri, sqrt(l));
	}
	printf("Done.\n");

}

void main()
{
	ViewDifferents(0, 1000, 1000, sqrt_cpu1);
	CalcTime();

	while (!kbhit());
}

