//		Richard Smith		Game Math
//
//		Stats program.  

#include 
#include 
#include 
#include 	// for accumulate
#include 
#include 
#include 
#include 
#include 

using namespace std;

double FindAverage( const vector & v1 );
double FindMedian( const vector & v1 );
double FindMeanLessOutliers( vector & v1 );
double FindIQR( const vector & v1 );
double FindStdDeviation( const vector & v1 );


int main()
{
	cout << "   This program will work on a list on numbers in a file. \n"
		 << "Make sure that that the file has no trailing blank lines. \n"
		 << "Please enter the name of the file you want to do stats on, \n"
		 << "including the file\'s extension (e.g. quiz2.txt) : " ;

	string userStr;
	cin >> userStr;	  cout << endl;

	ifstream fin;
	fin.open( userStr.data() );
	assert(fin.is_open());

	// get scores.
	vector< double >  v;
	double currentDouble;

	// Read entire file's values into vector.
	int j(1);
	do {
		fin >> currentDouble;
		cout << setw(6) << currentDouble << ", " ;
		
		if( j % 5 == 0) cout << endl;	// five numbers per line.

		v.push_back(currentDouble); 
		j++;
	} while( !fin.eof() ) ;
	fin.close();


	sort( v.begin(),  v.end() );  // sort scores, needed for calls below.

	double average = FindAverage( v );
	double median  = FindMedian( v ) ;
	double meanLessOut  = FindMeanLessOutliers( v ) ; 
	double iqr     = FindIQR( v ) ;
	double stdDeviation = FindStdDeviation( v ) ;

	cout << "\n\n\n\nThe average is: " << average << endl << endl;
	cout << "The median is: " << median << endl << endl;
	cout << "The average (ignoring outliers) is: " << meanLessOut << "\n\n";

	cout << "The IQR: " << iqr << endl << endl;
	cout << "The standard Deviation is: " << stdDeviation << endl << endl;

	return 0;
}

//  Find Mean.
double FindAverage( const vector & v1 )
{
	return	accumulate(v1.begin(), v1.end(), 0.0) / v1.size() ;
}

// Find the Median value.  Note that vector MUST be in sorted
// order for this function to work.
double FindMedian( const vector & v1 )
{
	if( v1.size() % 2 == 0 )		// If even
	{
		// average 2 medium elements
		return (v1[ (v1.size()/2)-1 ] + v1[(v1.size()/2)] ) / 2.0  ;
	}
	else
		return  v1[ (v1.size()/2) ] ;
}


// Find mean, ignoring the smallest and largest values. 
// For this fucntion to work, the vector MUST be in sorted order AND
// it must be at least 3 elements in size.
double FindMeanLessOutliers( vector & v1 )
{
	return  accumulate(v1.begin() + 1, v1.end() - 1, 0.0) / (v1.size() - 2) ;
}


// Find the distance between the top halves median & the lower halves median.
double FindIQR( const vector & v1 )
{
	double lowMedian, highMedian ;
	int halfPt( v1.size() / 2 );

	if( v1.size() % 2 == 0 )		// If even it splits evenly
	{
		vector lowHalf( v1.begin(), v1.begin() + halfPt );
		vector topHalf( v1.begin() + halfPt, v1.end() );
						// Why is addition legal in line above?
						// Note range copy constructor takes two iterators.
		
		highMedian = FindMedian( topHalf );
		lowMedian  = FindMedian( lowHalf );
	}					

	else   // if odd we must count center element in both upper & lower medians.
	{
		vector lowHalf( v1.begin(), v1.begin() + halfPt + 1 );
		vector topHalf( v1.begin() + halfPt, v1.end() );

		highMedian = FindMedian( topHalf );
		lowMedian  = FindMedian( lowHalf );
	}

	return highMedian - lowMedian ;
}


double FindStdDeviation( const vector & v1 )
{
	int size = v1.size();
	double varianceTotal( 0.0 );
	double average = FindAverage( v1 );

	{for(int j(0); j< size; j++ )
	{
		varianceTotal += pow((v1[j] - average), 2.0) ;
	}}
	//cout << "varianceTotal: " << varianceTotal << endl;

	return sqrt( (varianceTotal ) / ( size - 1.0) );
}

    Source: geocities.com/enigma1625