/*
 * grades_3.c
 * This program reads a number of grades, and computes statistics about them. 
 * The number of grades is unlimited.
 */

#include <stdio.h>
#include <math.h>

/* Prototypes: */
void comp_statistics (const int *arr, int n,
                      float *average, float *std_dev);

int main ()
{
  const int min_grade = 0;
  const int max_grade = 100;
  int       n_grades;          /* The number of grades. */
  int       *grades;           /* The grades. */
  int       count;             /* The number of grades currently read. */
  int       curr_grade;        /* The current grade. */
  float     average;           /* The average grade. */
  float     std_dev;           /* The standard deviation from the average. */
  int       n_above_avg;       /* Number of grades above the average. */
  int       i;

  /* Read the number of grades. */
  do
  {
    printf ("Please enter the number of grades: ");
    scanf ("%d", &n_grades);
  } while (n_grades < 0);

  /* Allocate memory. */
  grades = (int *) malloc (sizeof(int) * n_grades);

  /* Read the grades on by one. */
  count = 0;
  while (count < n_grades)
  {
    printf ("%d) Please enter the next grade: ", count + 1);
    scanf ("%d", &curr_grade);
    
    if (curr_grade < min_grade || curr_grade > max_grade)
    {
      printf ("Ignoring illegal grade (%d).\n", curr_grade);
      continue;
    }

    /* Store the grade. */
    grades[count] = curr_grade;
    count++;
  }

  /* Print out the grades and the statistics about them. */
  printf ("\nThe grades: \n");
  for (i = 0; i < n_grades; i++)
    printf ("%d ", grades[i]);
  printf ("\n");

  comp_statistics (grades, n_grades,
                   &average, &std_dev);

  printf ("Average grade is %g (dev = %g).\n", average, std_dev);

  /* Find how many students have a grade which is above the average. */
  n_above_avg = 0;
  for (i = 0; i < n_grades; i++)
  {
    if (grades[i] > average)
      n_above_avg++;
  }

  /* Note that we make sure that our output is grammatically correct: */
  printf ("%d student%s above the average.\n", 
          n_above_avg,
          (n_above_avg == 1) ? " is" : "s are");

  /* Free memory. */
  free (grades);

  return (0);
}

/* ------------------------------------------------------------------------
 * Function: comp_statistics
 * Purpose : Compute the average and standard deviation of an array of 
 *           integers.
 * Input   : arr     - The array.
 *           n       - Its size.
 * Output  : average - The average.
 *           std_dev - The standard deviation.
 * Returns : Nothing.
 */
void comp_statistics (const int *arr, int n,
                      float *average, float *std_dev)
{
  int       sum = 0;           /* The sum of all elements so far. */
  int       sum_sqrs = 0;      /* The sum of their squares. */
  float     variance;
  int       i;

  for (i = 0; i < n; i++)
  {
    sum += arr[i];
    sum_sqrs += arr[i]*arr[i];
  }

  /* Compute the average and variance,
     using the equality: Var(X) = E(X^2) - E(X)*E(X) */
  *average = (float)sum / (float)n;

  variance = (float)sum_sqrs / (float)n - (*average)*(*average);

  /* Compute the standard deviation. */
  *std_dev = sqrt(variance);

  return;
}

