diff --git a/1191225_ausgabe_tabelle.svg b/1191225_ausgabe_tabelle.svg new file mode 100644 index 0000000..d22f36e --- /dev/null +++ b/1191225_ausgabe_tabelle.svg @@ -0,0 +1,1379 @@ + + + + + + + + + + + + + + + + + Declare Variables: + row + year + + + + + + Declare Variables:... + + + + + + + + + + true + + + + true + + + + + + + + + + false + + + + false + + + + + + + + + row < rowCount + + + + row < rowCount + + + + + + + + + + + year = row + 1 + + + + year = row + 1 + + + + + + + + + + + row++ + + + + row++ + + + + + + + + + + + + + + + + + output_table + + + + + + output_table + + + + + + + + + + + + + print "\tinterest rate [%%] investment [€] annual interest [€]\n" + + + + + + + + + print "\tinterest rate [%%] investment [€] annual interest [€]\n" + + + + + + + + + + + Input: table, rowCount + + + + + Input: table, rowCount + + + + + + + + + + + Input: array, len + + + + Input: array, len + + + + + + + + + + + + Define Variables: + x = 0 + max = 0 + current = 0 + + + + + + Define Variables:max,current,x + + + + + + + + + + true + + + + true + + + + + + + + + + false + + + + false + + + + + + + + + x < len + + + + x < len + + + + + + + + + + true + + + + true + + + + + + + + + + false + + + + false + + + + + + + + + arr[x] > max + + + + arr[x] > max + + + + + + + + + + + current = x + + + + current = x + + + + + + + + + + + max = arr[x] + + + + max = arr[x] + + + + + + + + + + + + + + x++ + + + + x++ + + + + + + + + + + + return current + + + + return current + + + + + + + + + + + + + + + + find_index + + + + + + find_index + + + + + + + + + + + + print "year", year, "\t", table[row][0], "\t", table[row][1], "\t", table[row][2], "\n" + + + + print "year", year, "\t", table[row][0]"\t",table[row][1],"\t",table[row][2],"\n" + + + + + + + + + Text is not SVG - cannot display + + + diff --git a/1191225_erklärung.pdf b/1191225_erklärung.pdf new file mode 100644 index 0000000..c50455e Binary files /dev/null and b/1191225_erklärung.pdf differ diff --git a/1191225_program.c b/1191225_program.c new file mode 100644 index 0000000..42476f1 --- /dev/null +++ b/1191225_program.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include +#include + +#ifdef __cplusplus +#error *Please use a proper C-Compiler* +#endif + +// needed for reading proper input from stdin +#define MAX_LINE_LEN 100 + +#define STUDENT_INFO "Sven", "Vogel", 1191225 + +// name of the file to write to on --export +const char *FILE_NAME = "info_export.txt"; + +/** + * @brief read some unsigned int form stdin. The value must be within and including in the range between min and max. + * + * @param min minimum value + * @param max maximum value + * @param msg message + * @return unsigned int + */ +unsigned int read_ul(const unsigned int min, const unsigned int max, const char* restrict msg) { + // buffer to fit line from stdin + char line[MAX_LINE_LEN]; + // end of buffer + char *end = line + MAX_LINE_LEN; + + unsigned int value; + + do { + // print message + printf("%s", msg); + // flush stdout to make sure every char is written properly + fflush(stdout); + // read a line from stdin + fgets(line, MAX_LINE_LEN, stdin); + // parse line to unsigned long + value = strtoul(line, &end, 10); + + } while (value > max || value < min); + + return value; +} + +/** + * @brief read some double form stdin. The value must be within and including in the range between min and max. + * After each attempt to parse a meaningful value msg will be printed to stdout. + * + * @param min minimum value + * @param max maximum value + * @param msg message + * @return unsigned int + */ +double read_lf(const double min, const double max, const char* restrict msg) { + // buffer to fit line from stdin + char line[MAX_LINE_LEN]; + // end of buffer + char *end = line + MAX_LINE_LEN; + + double value; + + do { + // print message + printf("%s", msg); + // read a line from stdin + fgets(line, MAX_LINE_LEN, stdin); + // parse line to double + value = strtod(line, &end); + + } while (value > max || value < min); + + return value; +} + +/** + * @brief read interest rate and growth rate from stdin + * + * @param interestRate + * @param growthRate + * @return true + * @return false + */ +void input_rate_and_growth(double *interestRate, double *growthRate) { + + // input interest rate + *interestRate = read_lf(0.01, 10, "\tEnter interest rate [0.01; 10]: "); + + // input growth rate + *growthRate = read_lf(0.01, 5.0, "\tEnter growth rate [0.01; 5]: "); +} + +/** + * @brief fill tab with interest calculations. Each row will contain data for the next year. + * the columns will contain [0] := interest rate [1] := investment amount [2] := investment growth + * + * @param tab 3 column table + * @param duration number of years to calculate for + * @param investmentAmount start money + * @return double sum off total investments + */ +double calculate_interest_growth(double tab[][3], int duration, double investmentAmount) { + // declare variables + double interestRate; + double growthRate; + double totalInterests = 0; + + input_rate_and_growth(&interestRate, &growthRate); + + // initialize 1. year + tab[0][0] = interestRate; + tab[0][1] = investmentAmount; + tab[0][2] = investmentAmount * interestRate * 1e-2; + + for(unsigned int year = 1; year < duration; year++) { + unsigned int lastYear = year - 1; + + // investment = investment form last year + interest + tab[year][1] = tab[lastYear][1] + tab[lastYear][2]; + + // interest rate = last interest rate + interest growth + tab[year][0] = tab[lastYear][0] + growthRate; + + // interest = investmentAmount * interest rate + tab[year][2] = tab[year][1] * tab[year][0] * 1e-2; + + totalInterests += tab[year][2]; + } + + return totalInterests + tab[0][2]; +} + +/** + * @brief print the table tab as layouted for calculate_interest_growth() to stdout + * + * @param tab + * @param duration number of rows + */ +void output_table(double tab[][3], const unsigned int rows) { + printf("\n\tinterest rate [%%] investment [€] annual interest [€]\n"); + + unsigned int year = 0; + + // print each row of the table + for(unsigned int row = 0; row < rows; row++) { + year ++; + printf("year %2d:% 12.2lf\t% 12.2lf\t% 10.2lf\n", year, tab[row][0], tab[row][1], tab[row][2]); + } +} + +/** + * @brief find the maximum value in arr + * + * @param arr + * @param len + * @return unsigned int index of the maximum value in arr + */ +unsigned int find_index(double arr[], unsigned int len) { + unsigned int current = 0; + double max = 0; + + // look through the entire array + for (unsigned int x = 0; x < len; x++) { + // test if we have found sth bigger than before + if (arr[x] > max) { + current = x; + max = arr[x]; + } + } + + // return index of biggest found element + return current; +} + +typedef struct student { + const char* name; + const char* familyName; + // 7-Decimal-Digit UUID number + uint32_t matriculationNumber; +} Student; + +/** + * @brief create a new stack allocated student + * + * @param name forename of the student + * @param familyName + * @param matriculationNumber 7-digit unsigned uuid + * @return Student + */ +Student new_student(const char* restrict name, const char* restrict familyName, const uint32_t matriculationNumber) { + Student new_stud = { + .name = name, + .familyName = familyName, + .matriculationNumber = matriculationNumber, + }; + + return new_stud; +} + +/** + * @brief writes the format of student to the file specified by FILE_NAME. + * + * @param text + */ +void export_to_disk(const char* restrict text) { + + // open file in write mode only, truncating previous content to zero + FILE* handle = fopen(FILE_NAME, "w"); + + // file could not be opened + if (handle == NULL) { + fprintf(stderr, "could not open file to export\n"); + return; + } + + fprintf(handle, "%s", text); + + fclose(handle); + + printf("Author exported to disk. Goodbye!\n"); +} + +/** + * @brief fill a destination string with the format "Name , Matriekelnummer: " + * + * @param dest string to store in, should be 100 bytes in size + * @param author student to take inforamtion from + */ +void generate_string(char * restrict dest, const Student *student) { + sprintf(dest, "Name: %s %s, Matrikelnummer: %7d\n", student->name, student->familyName, student->matriculationNumber); +} + +int main(int argc, char **argv) { + + const Student author = new_student(STUDENT_INFO); + + unsigned int offerCount; + unsigned int years; + double investmentAmount; + + char info[100]; // hopefully no one ever has a name longer than 100 chars + + generate_string(info, &author); + + // parse command line argument + if (argc > 1 && strcmp(argv[1], "--info") == 0) { + printf("%s", info); + + if (argc > 2 && strcmp(argv[2], "--export") == 0) { + export_to_disk(info); + // abort, were done + return 0; + } + } + + // run for ever. or until the user decides to kill it. + while (1) { + + // input data + years = read_ul(1, 50, "Enter investment duration in years [1; 50]: "); + investmentAmount = read_lf(100, 10000, "Enter investment amount in € [100; 10000]: "); + offerCount = read_ul(1, 3, "Enter offer count [1; 3]: "); + + // allocate table + double (*tab)[3] = calloc(years, sizeof(double[3])); + + // allocate array for all offer sums + // alternative dynamic stack allocation: double totalInterests[offerCount]; + // alternative static stack allocation: double totalInterests[50]; + double *totalInterests = calloc(offerCount, sizeof(double)); + + for (int i = 0; i < offerCount; i++) { + printf("\n--------------------------------------------------------------\n"); + + // call berechne_zinswachtum() + double totalInterest = calculate_interest_growth(tab, years, investmentAmount); + + // save this offers total interest for later + totalInterests[i] = totalInterest; + + output_table(tab, years); + + printf("\nTotal interest after 3 years: %.2lf€\n", totalInterest); + } + + // find and print best offer + + unsigned int bestOffer = find_index(totalInterests, offerCount); + + printf("\n--------------------------------------------------------------\n"); + printf("***Offer %d has the best total interest with %.2lf€ after %d years***\n\n", bestOffer + 1, totalInterests[bestOffer], years); + printf("\n--------------------------------------------------------------\n"); + + // free resources + free(totalInterests); + free(tab); + } + + return 0; +} \ No newline at end of file diff --git a/1191225_such_index.svg b/1191225_such_index.svg new file mode 100644 index 0000000..48139a5 --- /dev/null +++ b/1191225_such_index.svg @@ -0,0 +1,1359 @@ + + + + + + + + + + + + + + + + + Declare Variables: + row + year + + + + + + Declare Variables:... + + + + + + + + + + true + + + + true + + + + + + + + + + false + + + + false + + + + + + + + + row < rowCount + + + + row < rowCount + + + + + + + + + + + year = row + 1 + + + + year = row + 1 + + + + + + + + + + + row++ + + + + row++ + + + + + + + + + + + + + + + + + output_table + + + + + + output_table + + + + + + + + + + + + + print "\tinterest rate [%%] investment [€] annual interest [€]\n" + + + + + + + + + print "\tinterest rate [%%] investment [€] annual interest [€]\n" + + + + + + + + + + + Input: table, rowCount + + + + + Input: table, rowCount + + + + + + + + + + + Input: array, len + + + + Input: array, len + + + + + + + + + + + + Define Variables: + x = 0 + max = 0 + current = 0 + + + + + + Define Variables:max,current,x + + + + + + + + + + true + + + + true + + + + + + + + + + false + + + + false + + + + + + + + + x < len + + + + x < len + + + + + + + + + + true + + + + true + + + + + + + + + + false + + + + false + + + + + + + + + arr[x] > max + + + + arr[x] > max + + + + + + + + + + + current = x + + + + current = x + + + + + + + + + + + max = arr[x] + + + + max = arr[x] + + + + + + + + + + + + + + x++ + + + + x++ + + + + + + + + + + + return current + + + + return current + + + + + + + + + + + + + + + + find_index + + + + + + find_index + + + + + + + + + + + + print "year", year, "\t", table[row][0], "\t", table[row][1], "\t", table[row][2], "\n" + + + + print "year", year, "\t", table[row][0]"\t",table[row][1],"\t",table[row][2],"\n" + + + + + + diff --git a/README.md b/README.md index 2afd284..236b59c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,29 @@ -# Zinsrechner +## DHBW interest calculator -Interest calculator source code for the practical project of semester 1 \ No newline at end of file +Program desgin from school. Function and variable names were translated to english. + +### Compatability with non ANSI terminal emulators + +For the best experience at least an ANSI or UTF-8 compatible terminal is required for special characters such as the € symbol. +Please note that a true C-Compiler is required to compile the code. If you don't have one in order to compile with a C++ compiler you may need to remove the macro at the start +testing for a C++ compiler and the `restrict` keyword. +This program was testet with the following operating systems: + +#### Windows 11 Pro (x86\_64) + +Tested for Version 10.0.22621 with SDK version 10.0.22000 for Microsoft Visual Studio 17 with MSVC 19.34.31937. + +NOTE: Due to cross platform compatability no “safe(r)” functions like `scanf_s` nor any of the `WINAPI` were used. The code should still compile and run without errors or warnings.  + +#### Linux (x86\_64) + +Tested for Archlinux with vanilla Kernel 6.0.11-arch1-1 and gcc 12.2.0. + +### Compile & Run + +The code can be freely compiled with any C/C++ compiler like clang, icc, gcc, etc… +With the source provided is a  build file for cmake (since this is the default tool I use to compile and test).  + +Build with cmake: + +`cmake . && cmake --build .` \ No newline at end of file