added source files as well as image files required for the project
These files were uploaded into the repository just for completeness.
This commit is contained in:
parent
d2cce5777b
commit
fb43562e05
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
@ -0,0 +1,304 @@
|
|||
#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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 48 KiB |
30
README.md
30
README.md
|
@ -1,3 +1,29 @@
|
|||
# Zinsrechner
|
||||
## DHBW interest calculator
|
||||
|
||||
Interest calculator source code for the practical project of semester 1
|
||||
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 .`
|
Loading…
Reference in New Issue