Solution to the statistics package program

/** 
NOTE 0: This is an approximation of the assignment. 
NOTE 1: I put all the array functions in this file 
   to make it easier to see all the code used in this assignment.  However, 
   I have added the array functions to the array file.   
   
NOTE 2: I calculated the location of the mode rather than the value of the
   mode so that I could more easily output "there is no mode" when there was
   no mode.

NOTE 3: It is much easier to find the median and mode if the array is sorted, 
   therefore, if the array was not sorted, I sorted it. The only subprograms
   that rely on the sorted array are the ones for median and mode.  I am 
   surprized that the sample output in Foster does not reflect the sorting. 
   If you wanted to maintain the original input order, you would need to have
   an array to hold the data in the original order and another one to hold the
   sorted array.  Can't see than maintaining the original order in this case
   is worth the extra memory or work.

NOTE 4: The function brendas_bubble() is a variation of bubble sort that is
   much more efficient than the traditional bubble sort.  Check it out.

NOTE 5: I added in the output for number of elements as shown in Foster as
   part of the show data selection.

NOTE 6: I added a "press return to continue message" just to show you an
   example of one way of accomplishing this.  Not very elegant but not an
   awful example.
**/

/********************************************************
*                                                       *
*  Brenda Sonderegger              Sept. 28, 1997       *
*                                                       *
*  CS210 - Assignment 4                                 *
*                                                       *
*  Purpose: Use 1-d arrays                              *
*                                                       *
*  Description: Create a menu driven statistics program *
*        that allows the user to choose to enter data,  *
*        display data, display the high and low datum,  *
*        display the mean, the mode, and the varience   *
*        and standard deviation.                        *
********************************************************/

#include <stdio.h>
#include <math.h> 
#include <ctype.h>
#include <stdlib.h>
#include "myio_c.h"

#define  MAX     20   
#define  TRUE     1
#define  FALSE    0    
#define  EPSILON  0.001

/* syntactic sugar */
#define  ADD_DATA 1
#define  WRITE    2
#define  HI_LOW   3
#define  MEAN     4
#define  MEDIAN   5
#define  MODE     6
#define  VAR_STD  7
#define  QUIT     8

void print_menu(void);
void fill_1d_float(float [], int, int, int *);
void write_1d_float(float [], int, int);
void brendas_bubble(float [], int, int);

float calc_mean(float [], int, int);
float calc_median(float [], int, int);
float calc_variance(float [], int, int, float);
int calc_mode_location(float [], int, int);
float calc_high(float [], int, int);
float calc_low(float [], int, int);



void main(void)
{
  char junk;
  int choice, actual_high = -1, sorted = 0, mode_location = -1;
  float data[MAX];
  float high, low, mean, median, variance, standard_dev; 

  high = low = mean = median = variance = standard_dev = -1.0;  

  do
  {
    print_menu();
    printf("\nEnter your choice now ");
    get_int_bound(&choice, 1, 8);
    if ((choice != 8) && (choice != 1) && (actual_high < 0 ))
       printf("\nNo data - you must enter data first.\n");
    else
    {
      switch(choice)
      {
        case ADD_DATA:
                fill_1d_float(data, actual_high + 1, MAX-1, &actual_high);
                high = low = mean = variance = standard_dev = -1;
                mode_location = -1;
                sorted = 0;
                break;
        case WRITE: printf("\nNumber of elements: %d\n", actual_high + 1);
                    write_1d_float(data, 0, actual_high);
                    printf("\n\n");
                    break;
        case HI_LOW: 
                if (sorted == 0)
                { 
                  low =  calc_low(data, 0, actual_high);
                  high = calc_high(data, 0, actual_high);
                }
                else
                {
                  low = data[0];
                  high = data[actual_high];
                }
                printf("\nHigh = %f, low = %f\n\n", high, low);
                break;
        case MEAN: mean = calc_mean(data, 0, actual_high);
                   printf("\nmean = %f\n\n", mean);
                   break;
        case MEDIAN: 
                if (sorted == 0) 
                {
                  brendas_bubble(data, 0, actual_high);
                  sorted = 1;
                }
                median = calc_median(data, 0, actual_high);
                printf("\nmedian = %f\n\n", median);
                break;
        case MODE: 
                if (sorted == 0) 
                {
                  brendas_bubble(data, 0, actual_high);
                  sorted = 1;
                }
                mode_location = calc_mode_location(data, 0, actual_high);
                if (mode_location >= 0)
                   printf("\nmode = %f\n\n", data[mode_location]);
                else
                   printf("\nThere is no mode\n\n");
                break;
        case VAR_STD:
                if (mean < 0)
                  mean = calc_mean(data, 0, actual_high);
                variance = calc_variance(data, 0, actual_high, mean); 
                standard_dev = sqrt(variance);
                printf("\nvariance = %f\nstandard deviation = %f\n\n", 
                           variance, standard_dev);
                break;
        case QUIT: printf("\nThanks for using the program \n");
      }
    }
    if (choice != 8)
    {
      printf("\nPress carriage return to continue ");
      scanf("%c", &junk);
      /** for safety, it would probably be a good idea to check to see
          if junk has a carriage return in it and if not, then clean the
          input stream
      **/
    }
  }
  while (choice != 8);
}


void print_menu(void)
{
   printf("\n\nStatistics Menu\n");
   printf("\n1 - Enter data");
   printf("\n2 - Display data");
   printf("\n3 - Calculate and display high value and low value");
   printf("\n4 - Calculate and display mean value ");
   printf("\n5 - Calculate and display median value");
   printf("\n6 - Calculate and display smallest mode ");
   printf("\n7 - Calculate and display the varience and standard diviation");
   printf("\n8 - quit");
}


/********fill_1d_float() is somewhat different than fill_1d_int_part() in 
   that I did not send a stopping value.  In this case, I choose to use a
   print statement and a local value to control the end of input.  Both
   methods are completely legitimate.  Which you use depends on personal
   preference, the problem to be solved, and other considerations.  No 1
   fill procedure will be correct for every array based problem.
************/

void fill_1d_float(float array[], int low, int high, int *actual)
{
   int index = low, done = FALSE;
   float temp;

   if (index <= high)
   {
     printf("\nEnter a -1.0 to indicate end of input.\n");
     do
     {
        printf("\nEnter item #%d ", index + 1);
        get_float_low(&temp, -1.0);
        if (temp < 0.0)
        {
          done = TRUE;
          *actual = index - 1;
        }
        else
        {
          array[index] = temp; 
          index++;
          if (index > high)
          {
            printf("\nEnd of input - array full.\n");
            *actual = index - 1;
          }
        }
     }
     while ((index <= high) && (done != TRUE));
   }
   else 
     printf("\nArray is full - no more data can be entered.\n");
}


void write_1d_float(float array[], int low, int high)
{
  int i;

  for (i = low; i <= high; i++)
    printf("%f ", array[i]);
}


float calc_high(float array[], int low, int high)
{
  int i;
  float biggest = array[low];

  for (i = low + 1; i <= high; i++)
  {
    if (array[i] > biggest)
       biggest = array[i];
  }
  return (biggest);
}


float calc_low(float array[], int low, int high)
{
  int i;
  float small = array[low];

  for (i = low + 1; i <= high; i++)
  {
    if (array[i] < small)
       small = array[i];
  }
  return (small);
}


float calc_mean(float array[], int low, int high)
{
  int i, num_elements = high - low + 1;
  float sum = 0.0;

  for (i = low; i <= high; i++)
  {
    sum = sum + array[i];
  }
  if (num_elements != 0)
    return (sum/num_elements);
  else
    return (0.0);
}

float calc_median(float array[], int low, int high)
{
  float median;
  int num_elements = high - low + 1;
  int middle = num_elements/2 + low;

  if (num_elements%2 == 1)
    median = array[middle];
  else
    median = (array[middle] + array[middle - 1])/2.0;
  return (median);
}


float calc_variance(float array[], int low, int high, float mean)
{
  float sum_squares = 0.0, value;
  int i, num_elements = high - low + 1;

  for (i = low; i <= high; i++)
  {
    value = mean - array[i];
    sum_squares = sum_squares + value * value;
  }
  if (num_elements > 0)
    return (sum_squares / num_elements);
  else
    return (0.0);
}


int calc_mode_location(float array[], int low, int high)
{
   float mode = array[low];
   int i, location = low, temp_locate = low, count = 0, temp_count = 1;

   for (i = low + 1; i <= high; i++)
   {
      if (fabs(array[i] - mode) < EPSILON)
      {
        temp_count++;
      }
      else
      {
        if (temp_count > count)
        {
          count = temp_count;
          location = i - 1;
        }
        mode = array[i];
        temp_count = 1;
      }
   }
   if (count > 1)
     return location;
   else
     return low - 1; 
}

void brendas_bubble(float array[], int low, int high)
{
  int i = low, j, sorted = FALSE;
  int count = 1;
  float temp;

  while ((sorted == FALSE) && (i <= high))
  {
     sorted = TRUE;
     for (j = low; j <= high - count; j++)
     {
        if (array[j] > array[j+1])
        {
           /** could call swap() instead of doing the swap here **/
           temp = array[j];
           array[j] = array[j+1];
           array[j+1] = temp;
           sorted = FALSE;
        }
     }
     i++;
     count++;
   }
}