Zinsrechner/1191225_program.c

304 lines
8.6 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>
#include <string.h>
#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 <NAME>, <FAMILYNAME> Matriekelnummer: <NUMBER>"
*
* @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;
}