/*
 * obs_list.c
 * This program reads a sequence of observations (real numbers), computes
 * their statistics and prints the deviation of each observation from the
 * average.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MAX_STRING 40

struct _Observation
{
  double              value;    /* The observation value. */
  struct _Observation *p_next;  /* Points to the next observation. */
};

typedef struct _Observation Observation;

int main ()
{
  char        in[MAX_STRING];
  Observation *p_first = NULL;  /* The first observation. */
  Observation *p_last = NULL;   /* The last observation so far. */
  Observation *p_curr = NULL;   /* The current observation. */
  int         n_obs = 0;        /* Nunber of observations so far. */
  double      sum_obs = 0;      /* The sum of all observations. */
  double      sum_sqr_obs = 0;  /* The sum of their squares. */
  double      mean;             /* The mean observation. */
  double      std_dev;          /* The standard deviation. */
  int         i;
  
  while (1)
  {
    /* Read the current user input. */
    printf ("Please enter an observation (or . to quit): ");
    scanf ("%s", in);

    /* Stop in case of a "." input. */
    if (strcmp(in, ".") == 0)
      break;

    /* Create a new observation. */
    p_curr = (Observation *) malloc (sizeof(Observation));
    p_curr->value = atof (in);
    p_curr->p_next = NULL;

    /* Update sums. */
    n_obs++;
    sum_obs += p_curr->value;
    sum_sqr_obs += (p_curr->value)*(p_curr->value);

    /* Make it the last observation. */
    if (p_last != NULL)
    {
      /* Link p_curr after p_last and update the p_last pointer. */
      p_last->p_next = p_curr;
      p_last = p_curr;
    }
    else
    {
      /* No observations so far: p_curr is the first and last one. */
      p_first = p_curr;
      p_last = p_curr;
    }
  }

  /* Stop here if there are no observations. */
  if (n_obs == 0)
  {
    printf ("No observations.\n");
    return (0);
  }

  /* Compute the mean and standard deviation of all observations. */
  mean = sum_obs / n_obs;
  std_dev = sqrt (sum_sqr_obs / n_obs - mean*mean);

  printf ("Mean of all observations: %g, standard deviation: %g\n",
          mean, std_dev);

  /* Go over all observations and print their deviations from the mean. */
  p_curr = p_first;
  i = 1;

  while (p_curr != NULL)
  {
    printf ("Observation no. %d: %g (%g*sigma).\n",
            i, p_curr->value, (p_curr->value - mean) / std_dev);

    /* Move to the next observation. */
    i++;
    p_curr = p_curr->p_next;
  }

  /* Free memory. */
  while (p_first != NULL)
  {
    /* Keep a pointer to the second observation. */
    p_curr = p_first->p_next;

    /* Free the first observation. */
    free (p_first);

    /* Update the pointer to the first observation. */
    p_first = p_curr;
  }

  return (0);
}

