#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>

char *pname;
char *in_file;

#define DATA_COUNT	(1024*1024)
u_int64_t data_items[DATA_COUNT];

int num_data_items = 0;

#define BUFSIZE		1024
char in_buf[BUFSIZE];

static int
compare_long(const void *p1, const void *p2)
{
	u_int64_t val1 = *(u_int64_t *)p1;
	u_int64_t val2 = *(u_int64_t *)p2;

	if (val1 == val2)
		return 0;
	if (val1 < val2)
		return -1;
	return 1;
}

int
main(int argc, char **argv)
{
	FILE *in_fp;
	u_int64_t sum_x = 0;
	u_int64_t sum_sq_x = 0;
	u_int64_t mean;
	double std_dev;
	int i;
	int one_sd = 0;
	int two_sd = 0;
	int three_sd = 0;
	double one_sd_low, one_sd_high;
	double two_sd_low, two_sd_high;
	double three_sd_low, three_sd_high;

	pname = argv[0];
	if (argc == 1)
		in_fp = stdin;
	else {
		in_file = argv[1];
		in_fp = fopen(in_file, "r");
	}
	while (fgets(in_buf, BUFSIZE, in_fp)) {
		if (num_data_items == DATA_COUNT) {
			fprintf(stderr,
				"DATA overflow, increase size of data_items array\n");
			exit(1);
		}
		sscanf(in_buf, "%ju", &data_items[num_data_items]);
#if 0
		printf("%lu\n", data_items[num_data_items++]);
#endif
		num_data_items++;
	}
	if (num_data_items == 0) {
		fprintf(stderr, "Empty input file ?\n");
		exit(1);
	}
#if 0
	printf("Total items %lu\n", num_data_items);
#endif
	for (i = 0 ; i < num_data_items ; i++) {
		sum_x += data_items[i];
		sum_sq_x += data_items[i] * data_items[i];
	}
	mean = sum_x / num_data_items;
	printf("\tMean %lu\n", mean);
	std_dev = sqrt((sum_sq_x / num_data_items) - (mean * mean));
	printf("\tStd Dev %.2f (%.2f%% of mean)\n",
	       std_dev, (std_dev * 100.0) / mean);
	one_sd_low = mean - std_dev;
	one_sd_high = mean + std_dev;
	two_sd_low = mean - (2 * std_dev);
	two_sd_high = mean + (2 * std_dev);
	three_sd_low = mean - (3 * std_dev);
	three_sd_high = mean + (3 * std_dev);
	for (i = 0 ; i < num_data_items ; i++) {
		if (data_items[i] >= one_sd_low &&
		    data_items[i] <= one_sd_high)
			one_sd++;
		if (data_items[i] >= two_sd_low &&
		    data_items[i] <= two_sd_high)
			two_sd++;
		if (data_items[i] >= three_sd_low &&
			 data_items[i] <= three_sd_high)
			three_sd++;
	}
	printf("\tWithin 1 SD %.2f%%\n",
	       ((double)one_sd * 100) / num_data_items);
	printf("\tWithin 2 SD %.2f%%\n",
	       ((double)two_sd * 100) / num_data_items);
	printf("\tWithin 3 SD %.2f%%\n",
	       ((double)three_sd* 100) / num_data_items);
	printf("\tOutside 3 SD %.2f%%\n",
	       ((double)(num_data_items - three_sd) * 100) / num_data_items);
	/* Sort the data to get percentiles */
	qsort(data_items, num_data_items, sizeof(u_int64_t), compare_long);
	printf("\t50th percentile %lu\n", data_items[num_data_items / 2]);
	printf("\t75th percentile %lu\n", data_items[(3 * num_data_items) / 4]);
	printf("\t90th percentile %lu\n", data_items[(9 * num_data_items) / 10]);
	printf("\t99th percentile %lu\n", data_items[(99 * num_data_items) / 100]);
}