Created
April 5, 2018 19:39
-
-
Save etscrivner/3d4912798094fb0b57131e0931c109ae to your computer and use it in GitHub Desktop.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| ** 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 */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| ** 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 */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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"); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| ** 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