{{ message }}

Instantly share code, notes, and snippets.

# etscrivner/main.c

Created Apr 5, 2018
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 #include #include #include #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 #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 #include #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 */