Skip to content

Instantly share code, notes, and snippets.

@etscrivner etscrivner/main.c
Created Apr 5, 2018

Embed
What would you like to do?
Exercise 1A. Write a program to estimate the mean and standard deviation of a sample of n real numbers. Use a linked list to hold the n numbers for the calculation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "result.h"
#include "number_list.h"
#include "population_statistics.h"
eResult read_numbers(NumberList *number_list)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** next_number double Holds the next numerical input from standard input.
** buffer char[256] Buffer for holding input from the user.
*/
double next_number;
char buffer[256];
/* [ number_list is invalid -> return invalid number list error ] */
if ( number_list == NULL )
{
return(kResultInvalidNumberList);
}
/* [ number_list := all numbers from standard input ] */
{
while ( feof(stdin) == 0 )
{
/* [ unable to read from input stream -> return success value
| true -> attempt to parse number from input ] */
if ( fgets(buffer, 256, stdin) == NULL )
{
return(kResultSuccess);
}
else
{
/* [ if newline not in buffer -> reject input and clear input
| true -> parse the number and add to list ] */
if ( !strchr(buffer, '\n') )
{
/* [ reject input and read until newline or error ] */
while ( fgets(buffer, 256, stdin) && !strchr(buffer, '\n') )
{
/* [ do nothing ] */
}
}
else
{
/* [ value, endchr := number from buffer, last unparsed character ] */
char *endchr;
next_number = strtod(buffer, &endchr);
/* [ last unparsed character is space or 0 -> append number to list
| true -> print error and return invalid input error ] */
if ( isspace(*endchr) || *endchr == 0 )
{
NumberList_append(number_list, next_number);
}
else
{
printf("%s is not a valid 64-bit real input\n", buffer);
return(kResultInvalidInput);
}
}
}
}
}
return(kResultSuccess);
}
int main(void)
{
/*
** LOCAL VARIABLES:
**
** Variable Type Description
** -------- ---- -----------
** command_result eResult Result from commands executed.
** This value ultimately indicates
** the exit condition of the
** program.
** number_list NumberList* List of numbers retrieved from
** user input.
** population_statistics PopulationStatistics Statistics for number list
** values.
*/
eResult command_result;
NumberList *number_list;
PopulationStatistics population_statistics;
/* [ number_list := new number list ] */
number_list = NumberList_create();
/* [ command_result, number_list = result of input, numbers from input ] */
command_result = read_numbers(number_list);
/* [ command_result is success ->
compute and display population statistics ] */
if ( command_result == kResultSuccess )
{
/* [ command_result, population_statistics :=
result of computing population statistics, population statistics ] */
command_result = PopulationStatistics_compute(
number_list, &population_statistics
);
/* [ command_result is success -> display population statistics ] */
if ( command_result == kResultSuccess )
{
/* [ command_result := result of displaying population statistics ] */
command_result = PopulationStatistics_display(&population_statistics);
}
}
/* [ destroy number_list ] */
NumberList_destroy(number_list);
/* [ if command_result is not success -> display error and terminate failed
| true -> terminate successful ] */
if ( command_result != kResultSuccess )
{
printf("error: %s\n", Result_message(command_result));
return(EXIT_FAILURE);
}
return(EXIT_SUCCESS);
}
#include <stdlib.h>
#include "number_list.h"
NumberListNode* NumberListNode_create(double value)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** result NumberListNode* Number list node returned on success
*/
NumberListNode *result;
/* [ result := allocate NumberListNode size bytes ] */
result = (NumberListNode*)calloc(1, sizeof(NumberListNode));
/* [ result of succeeded -> assigned value and return result
| true -> return failed allocation result ] */
if ( result != NULL )
{
result->value = value;
}
return(result);
}
eResult NumberListNode_destroy(NumberListNode *number_list_node)
{
/* [ free number_list_node ] */
free(number_list_node);
/* [ return success ] */
return(kResultSuccess);
}
NumberList* NumberList_create(void)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** result NumberList* Number list returned on success
*/
NumberList *result;
/* [ result := allocate NumberList size bytes ] */
result = (NumberList*)calloc(1, sizeof(NumberList));
/* [ allocation failed -> return failed allocation result
| true -> return successful allocation result ] */
return(result);
}
eResult NumberList_append(NumberList *number_list, double value)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** new_element NumberListNode* New element to be added to number list.
** last_element NumberListNode* Last element in the number list.
*/
NumberListNode *new_element;
NumberListNode *last_element;
/* [ number_list is invalid -> return invalid number list error ] */
if ( number_list == NULL )
{
return(kResultInvalidNumberList);
}
/* [ new_element, last_element :=
new number list node with value, tail(number_list) ] */
new_element = NumberListNode_create(value);
last_element = number_list->tail;
/* [ new_element is invalid -> return memory allocation failure */
if ( new_element == NULL )
{
return(kResultMemoryAllocationFailure);
}
/* [ last_element is empty -> set head and tail to new_element
| true -> append new_element to tail of list ] */
if ( last_element == NULL )
{
/* [ head(number_list), tail(number_list) := new_element, new_element ] */
number_list->head = new_element;
number_list->tail = new_element;
}
else
{
/* [ next(last_element), prev(new_element), tail(number_list) :=
new_element, last_element, new_element ] */
last_element->next = new_element;
new_element->prev = last_element;
number_list->tail = new_element;
}
/* [ return success ] */
return(kResultSuccess);
}
eResult NumberList_destroy(NumberList *number_list)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** next_element NumberListNode* Next node in the number list.
** current_element NumberListNode* Element to be released.
*/
NumberListNode *next_element;
NumberListNode *current_element;
/* [ number_list is valid -> free the list and all its elements
| true -> do nothing and return success ] */
if ( number_list != NULL )
{
/* [ next_element := head(number_list) ] */
next_element = number_list->head;
/* [ next_element := NULL value at end of list ] */
while ( next_element != NULL )
{
/* [ current_element, next_element :=
next_element, next(next_element) ] */
current_element = next_element;
next_element = next_element->next;
/* [ destroy current_element ] */
NumberListNode_destroy(current_element);
}
/* [ free number list ] */
free(number_list);
}
/* [ return success ] */
return(kResultSuccess);
}
int NumberList_length(NumberList *number_list)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** length int Accumulator for the length of the number
** list.
** next_element NumberListNode* Next element in the number list.
*/
int length;
NumberListNode *next_element;
/* [ number_list is invalid -> return -1 for length
| true -> return length of number list ] */
if ( number_list == NULL )
{
return(-1);
}
/* [ next_element, length := head(number_list), 0 ] */
next_element = number_list->head;
length = 0;
/* [ next_element, length := NULL at end of list, length of number_list ] */
while ( next_element != NULL )
{
/* [ next_element, length := next(next_element), length + 1 ] */
next_element = next_element->next;
length += 1;
}
/* [ return length ] */
return(length);
}
/*
** TYPES:
**
** Name Type Description
** ---- ---- -----------
** NumberListNode struct Node in a list of numbers.
** NumberList struct Simple abstraction of number list nodes. Only contains
** a pointer to the root node in the number list.
**
** INTERFACES:
**
** Name Description
** ---- ------------
** NumberList_create Creates a new number list. Returns NULL if allocation
** fails.
** NumberList_append Appends a new node containing the given value to the
** number list given. Returns an error result if appending
** fails.
** NumberList_destroy Destroy the number list given, deallocating all memory.
** The pointer given will no longer be valid after calling.
** Always returns a success result.
** NumberList_length Returns the length of the number list. Returns -1 if the
** list is invalid.
** NUMBERLIST_FORALL Loop over all of the elements in a number list performing
** some operation with each element. Should not be used to
** mutate list elements.
*/
#ifndef PSP_EXERCISE_1A_NUMBER_LIST_H_INCLUDED
#define PSP_EXERCISE_1A_NUMBER_LIST_H_INCLUDED
#include "result.h"
typedef struct NumberListNode_t {
struct NumberListNode_t *next; /* The node following this one */
struct NumberListNode_t *prev; /* The node preceding this one */
double value; /* Numeric value stored in this node */
} NumberListNode;
typedef struct NumberList_t {
NumberListNode *head; /* Head of the number list */
NumberListNode *tail; /* Tail of the number list */
} NumberList;
NumberList* NumberList_create(void);
eResult NumberList_append(NumberList*,double);
eResult NumberList_destroy(NumberList*);
int NumberList_length(NumberList*);
#define NUMBERLIST_FORALL(NUMBER_LIST, NODE) \
for ( NODE = NUMBER_LIST->head; \
NODE != NULL; \
NODE = NODE->next )
#endif /* PSP_EXERCISE_1A_NUMBER_LIST_H_INCLUDED */
#include <math.h>
#include <stdio.h>
#include "population_statistics.h"
eResult PopulationStatistics_compute(
NumberList *number_list,
PopulationStatistics *population_statistics)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** node NumberListNode* Next node in the number list.
** temp double Temporarily value for intermediate
** computations.
** list_length int Length of number list.
*/
NumberListNode *node;
double temp;
int list_length;
/* [ number_list is invalid -> return invalid number list error
| population_statistics is invalid -> return invalid stats error ] */
if ( number_list == NULL )
{
return(kResultInvalidNumberList);
}
if ( population_statistics == NULL )
{
return(kResultInvalidPopulationStats);
}
/* [ list_length := length of number_list ] */
list_length = NumberList_length(number_list);
/* [ list_length < 2 -> return too few items error ] */
if ( list_length < 2 )
{
return(kResultTooFewItems);
}
/* [ population_statistics.mean := average of number_list values ] */
{
/* [ population_statistics.mean := 0 ] */
population_statistics->mean = 0;
/* [ population_statistics.mean := sum of number_list values ] */
NUMBERLIST_FORALL(number_list, node)
{
population_statistics->mean += node->value;
}
/* [ population_statistics.mean :=
population_statistics.mean / list_length ] */
population_statistics->mean /= (double) list_length;
}
/* [ population_statistics.variance := variance of number_list values ] */
{
/* [ population_statistics.variance := 0 ] */
population_statistics->variance = 0;
/* [ population_statistics.variance :=
sum of (number_list value - population_statistics.mean)^2 ] */
NUMBERLIST_FORALL(number_list, node)
{
temp = node->value - population_statistics->mean;
population_statistics->variance += temp * temp;
}
/* [ population_statistics.variance :=
population_statistics.variance / (list_length - 1) ] */
population_statistics->variance /= (double)(list_length - 1);
}
/* [ population_statistics.standard_deviation :=
square_root(population_statistics.variance) ] */
population_statistics->standard_deviation = sqrt(
population_statistics->variance
);
/* [ return success ] */
return(kResultSuccess);
}
eResult PopulationStatistics_display(
PopulationStatistics *population_statistics)
{
/*
** LOCAL VARIABLES:
**
** Name Type Description
** ---- ---- -----------
** print_result int Result of printing to standard output.
*/
int print_result;
/* [ population_statistics is invalid -> return invalid stats error ] */
if ( population_statistics == NULL )
{
return(kResultInvalidPopulationStats);
}
/* [ stdout, print_result :=
"Mean: " + population_statistics.mean + newline,
result of printing to standard output ] */
print_result = printf("Mean: %.02lf\n", population_statistics->mean);
/* [ print_result indicates error -> return display stats failure ] */
if ( print_result < 0 )
{
return(kResultDisplayStatsFailure);
}
/* [ stdout, print_result :=
"Std. Dev.: " + population_statistics.mean + newline,
result of printing to standard output ] */
print_result = printf(
"Std. Dev.: %.02lf\n", population_statistics->standard_deviation
);
/* [ print_result indicates error -> return display stats failure
| true -> return success ] */
if ( print_result < 0 )
{
return(kResultDisplayStatsFailure);
}
return(kResultSuccess);
}
/*
** TYPES:
**
** Name Type Description
** ---- ---- -----------
** PopulationStatistics struct Container for derived population statistics.
**
** INTERFACES:
**
** Name
** PopulationStatistics_compute Computes population statistics for the given
** number list. Returns an error if there are
** too few list items.
** PopulationStatistics_display Displays the given population statistics to
** standard output. Returns an error if output
** fails.
*/
#ifndef PSP_EXERCISE_1A_POPULATION_STATISTICS_H_INCLUDED
#define PSP_EXERCISE_1A_POPULATION_STATISTICS_H_INCLUDED
#include "result.h"
#include "number_list.h"
typedef struct PopulationStatistics_t {
double mean;
double variance;
double standard_deviation;
} PopulationStatistics;
eResult PopulationStatistics_compute(NumberList*,PopulationStatistics*);
eResult PopulationStatistics_display(PopulationStatistics*);
#endif /* PSP_EXERCISE_1A_POPULATION_STATISTICS_H_INCLUDED */
#include "result.h"
const char* Result_message(eResult result)
{
switch (result)
{
case kResultSuccess:
return("Success");
case kResultInvalidInput:
return("User input was invalid");
case kResultComputeStatsFailure:
return("Computing population statistics failed");
case kResultDisplayStatsFailure:
return("Displaying population statistics failed");
case kResultMemoryAllocationFailure:
return("Memory allocation failed");
case kResultInvalidNumberList:
return("Number list provided is invalid");
case kResultInvalidPopulationStats:
return("Population statistics were invalid");
case kResultTooFewItems:
return("Too few items in number list");
default:
return("Invalid result");
}
}
/*
** TYPES:
**
** Name Type Description
** ---- ---- -----------
** eResult int Enumeration of subroutine result return values. Meant to be
** a complete enumeration of all program error conditions.
**
** INTERFACES:
**
** Name Description
** ---- -----------
** Result_message Returns the static error message associated with the given
** result value.
*/
#ifndef PSP_EXERCISE_1A_RESULT_H_INCLUDED
#define PSP_EXERCISE_1A_RESULT_H_INCLUDED
typedef enum eResult_t {
kResultSuccess, /* Subroutine executed successfully */
kResultInvalidInput, /* User input was invalid */
kResultComputeStatsFailure, /* Computing population statistics failed */
kResultDisplayStatsFailure, /* Displaying population statistics failed */
kResultMemoryAllocationFailure, /* Memory allocation failed */
kResultInvalidNumberList, /* Number list provided as input is invalid */
kResultInvalidPopulationStats, /* Population statistics provided are invalid */
kResultTooFewItems /* Too few items in number list */
} eResult;
const char* Result_message(eResult);
#endif /* PSP_EXERCISE_1A_RESULT_H_INCLUDED */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.