/*
Martin Sparre, December 2007.
gcc -lm -o histogram.o histogram.c

./Histogram.o filnavn.dat 10
(10 is the number of bins)
*/

//Libraries:
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

//Functions:
int NumberOfLines(char *);
void ReadInputFile(char *, int);
void CreateHistogram(void);
void CalcMaxMin(void);
void CreateHistogramArray(void);
void CreateIntervalsArray(void);
void CalculateBinNumber(double);
void CalculateBinNumberFAST(double);
void PrintHistogram(void);

//ints and doubles:
int NumberOfPoints;
int NumberOfBins;
double MaxValue;
double MinValue;
double dx; //BinWidth
double Points[100000000];
double Intervals[10000000];
double Histogram[10000000];

int main(int argc,char *argv[])
{
	char *NameOfInputFile = argv[1];
	NumberOfBins = atoi(argv[2]);
	
	NumberOfPoints=NumberOfLines(NameOfInputFile);

	ReadInputFile(NameOfInputFile, NumberOfPoints);

	CreateHistogram();

	PrintHistogram();

	return 0;
}

int NumberOfLines(char *Name)
{
	FILE *InputFile= fopen(Name,"r+");
	
	int c;
	int nl=0;
	while((c=getc(InputFile)) != EOF)
	{
		if(c=='\n')
		{
			nl++;
		}
	}
	fclose(InputFile);
	return nl;
}

void ReadInputFile(char *Name, int aNumberOfPoints)
{
	FILE *InputFile;
	InputFile = fopen(Name,"r+");
	
	int i;
	for(i=0;i< aNumberOfPoints;i++)
	{
		fscanf(InputFile, "%lf", &Points[i]);
	}
	fclose(InputFile);
}

void CalcMaxMin(void)
{
	double temp1=Points[0];
	double temp2=Points[0];
	
	int i;
	for(i=0;i<NumberOfPoints;i++)
	{
		if(Points[i]>temp1)
			temp1=Points[i];
		
		if(Points[i]<temp2)
			temp2=Points[i];
	}
	
	MaxValue=temp1;
	MinValue=temp2;
}

void CreateHistogramArray(void)
{
	int i;
	for(i=0;i<NumberOfBins;i++)
	{
		Histogram[i]=0.;
	}
}

void CreateIntervalsArray(void)
{
	dx=fabs(MaxValue-MinValue)/NumberOfBins;
	int i;
	for(i=0;i<NumberOfBins;i++)
	{
		Intervals[i]=MinValue+i*dx+0.5*dx;
	}
}

void CreateHistogram(void)
{
	CalcMaxMin();
	CreateHistogramArray();
	CreateIntervalsArray();
	
	int i;
	for(i=0;i<NumberOfPoints;i++)
	{
		CalculateBinNumberFAST(Points[i]);
	}
}

void CalculateBinNumber(double aValue)
{
	if(aValue==MinValue)
	{
			Histogram[0]=Histogram[0]+1.0;
	}
	else if(aValue==MaxValue)
	{
		Histogram[NumberOfBins-1]=Histogram[NumberOfBins-1]+1.0;
	}
	else
	{	
		int j;
		for(j=0;j<NumberOfBins;j++)
		{	
			if(fabs(aValue-Intervals[j])<dx/2.0)
			{
				Histogram[j]=Histogram[j]+1.0;
				break;
			}
			else if(fabs(aValue-Intervals[j]) == dx/2.0)
			{
				Histogram[j]=Histogram[j]+0.5;
			}
		}	
	}
}

void CalculateBinNumberFAST(double aValue)
{
	if(aValue==MinValue)
	{
			Histogram[0] = Histogram[0]+1.0;
	}
	else if(aValue==MaxValue)
	{
		Histogram[NumberOfBins-1]=Histogram[NumberOfBins-1]+1.0;
	}
	else
	{
		double BinNumber = (aValue-MinValue)/dx;
		int BinNumberINT = (aValue-MinValue)/dx;

		if(fabs(aValue-Intervals[BinNumberINT])<=dx/2.0)
		{
			Histogram[BinNumberINT]=Histogram[BinNumberINT]+1.0;
		}
		else if(fabs(aValue-Intervals[BinNumberINT]) == dx/2.0)
		{
			Histogram[BinNumberINT]=Histogram[BinNumberINT]+0.5;
			Histogram[BinNumberINT-1]=Histogram[BinNumberINT-1]+0.5;
		}
	}
}

void PrintHistogram(void)
{
	int i;
	double N=0;
	for(i=0;i<NumberOfBins;i++)
	{
		printf("%lf \t %lf \n", Intervals[i],Histogram[i]);
	}
}


