diff --git a/sk2/Makefile b/sk2/Makefile new file mode 100644 index 0000000..77b4f0b --- /dev/null +++ b/sk2/Makefile @@ -0,0 +1,22 @@ +CC = gcc +CFLAGS = -Wall -Wextra -std=c99 -pedantic -lm +TARGET = calculator + +all: $(TARGET) + +$(TARGET): main.o calculator.o + $(CC) $(CFLAGS) -o $(TARGET) main.o calculator.o -lm + +main.o: main.c calculator.h + $(CC) $(CFLAGS) -c main.c + +calculator.o: calculator.c calculator.h + $(CC) $(CFLAGS) -c calculator.c + +clean: + rm -f *.o $(TARGET) + +run: $(TARGET) + ./$(TARGET) + +.PHONY: all clean run diff --git a/sk2/README.md b/sk2/README.md new file mode 100644 index 0000000..b7d8b0d --- /dev/null +++ b/sk2/README.md @@ -0,0 +1,55 @@ +# Vedecká kalkulačka + +## Zadanie +Naprogramujte vedeckú kalkulačku, ktorá vyhodnocuje matematické výrazy v infixovej notácii s podporou základných operácií a matematických funkcií. + +## Požiadavky +- Načítanie a práca s číslami s presnosťou minimálne 2 desatinné miesta +- Podpora základných operácií: sčítanie (+), odčítanie (-), násobenie (*), delenie (/), zátvorky +- Podpora matematických funkcií: sinus (sin), kosínus (cos), druhá odmocnina (sqrt), druhá mocnina (^), dekadický logaritmus (log) + +## Funkcionalita +Kalkulačka: +1. Načíta matematický výraz z príkazového riadku +2. Prevedie infixový zápis na postfixový (RPN) +3. Vyhodnotí výraz pomocou zásobníkového algoritmu +4. Vypíše výsledok s presnosťou na 2 desatinné miesta +5. Podporuje interaktívny režim so zadaním "koniec" pre ukončenie + +## Opis riešenia +Riešenie využíva algoritmus shunting-yard (železničný zoraďovací algorimus) pre prevod infixovej notácie na postfixovú (RPN). Následne sa RPN výraz vyhodnotí pomocou zásobníka. + +### Hlavné kroky: +1. **Analýza vstupu**: Lexikálna analýza vstupného reťazca +2. **Konverzia na RPN**: + - Použitie dvoch zásobníkov: jeden pre operátory/funkcie, druhý pre výstup + - Respektovanie priorít operátorov a asociativity + - Spracovanie matematických funkcií +3. **Vyhodnotenie RPN**: + - Zásobníkový algoritmus pre vyhodnotenie + - Aplikácia operátorov a funkcií +4. **Výstup**: Formátovanie výsledku na 2 desatinné miesta + +### Podporované výrazy: +- Jednoduché aritmetické operácie: `2 + 3 * 4` +- Zátvorky: `(2 + 3) * 4` +- Matematické funkcie: `sin(0)`, `cos(0)`, `sqrt(25)`, `log(100)` +- Mocniny: `2^3`, `4^0.5` +- Komplexné výrazy: `sin(0) + cos(0) * 2` + +## Podmienky pre správne fungovanie +1. Program vyžaduje matematickú knižnicu (libm) +2. Vstupné výrazy musia byť matematicky korektné +3. Zátvorky musia byť správne párové +4. Delenie nulou spôsobí chybu +5. Logaritmus a odmocnina zo záporného čísla spôsobí chybu + +## Inštalácia a spustenie +```bash +# Kompilácia +make + +# Spustenie +make run +# alebo +./calculator diff --git a/sk2/calculator b/sk2/calculator new file mode 100755 index 0000000..653970e Binary files /dev/null and b/sk2/calculator differ diff --git a/sk2/calculator.c b/sk2/calculator.c new file mode 100644 index 0000000..f7ccf32 --- /dev/null +++ b/sk2/calculator.c @@ -0,0 +1,328 @@ +#include "calculator.h" +#include +#include +#include +#include +#include + +#define MAX_STACK_SIZE 256 +#define MAX_TOKEN_LENGTH 100 + +typedef struct { + double data[MAX_STACK_SIZE]; + int top; +} Stack; + +typedef struct { + char data[MAX_STACK_SIZE][MAX_TOKEN_LENGTH]; + int top; +} StringStack; + +static void init_stack(Stack *s) { + s->top = -1; +} + +static bool is_stack_empty(Stack *s) { + return s->top == -1; +} + +static bool is_stack_full(Stack *s) { + return s->top == MAX_STACK_SIZE - 1; +} + +static void push(Stack *s, double value) { + if (!is_stack_full(s)) { + s->data[++s->top] = value; + } +} + +static double pop(Stack *s) { + if (!is_stack_empty(s)) { + return s->data[s->top--]; + } + return 0.0; +} + +static void init_string_stack(StringStack *s) { + s->top = -1; +} + +static bool is_string_stack_empty(StringStack *s) { + return s->top == -1; +} + +static bool is_string_stack_full(StringStack *s) { + return s->top == MAX_STACK_SIZE - 1; +} + +static void push_string(StringStack *s, const char *str) { + if (!is_string_stack_full(s) && strlen(str) < MAX_TOKEN_LENGTH) { + strcpy(s->data[++s->top], str); + } +} + +static char* pop_string(StringStack *s) { + if (!is_string_stack_empty(s)) { + return s->data[s->top--]; + } + return NULL; +} + +static char* peek_string(StringStack *s) { + if (!is_string_stack_empty(s)) { + return s->data[s->top]; + } + return NULL; +} + +bool is_operator(char c) { + return c == '+' || c == '-' || c == '*' || c == '/' || c == '^'; +} + +int get_priority(char op) { + switch (op) { + case '+': + case '-': + return 1; + case '*': + case '/': + return 2; + case '^': + return 3; + default: + return 0; + } +} + +bool is_function(const char *str, int *length) { + if (strncmp(str, "sin", 3) == 0) { + *length = 3; + return true; + } + if (strncmp(str, "cos", 3) == 0) { + *length = 3; + return true; + } + if (strncmp(str, "sqrt", 4) == 0) { + *length = 4; + return true; + } + if (strncmp(str, "log", 3) == 0) { + *length = 3; + return true; + } + return false; +} + +double apply_operator(double a, double b, char op) { + switch (op) { + case '+': return a + b; + case '-': return a - b; + case '*': return a * b; + case '/': + if (b == 0) { + return NAN; + } + return a / b; + case '^': return pow(a, b); + default: return NAN; + } +} + +double apply_function(const char *func, double value, bool *error) { + if (strcmp(func, "sin") == 0) { + return sin(value); + } + if (strcmp(func, "cos") == 0) { + return cos(value); + } + if (strcmp(func, "sqrt") == 0) { + if (value < 0) { + *error = true; + return NAN; + } + return sqrt(value); + } + if (strcmp(func, "log") == 0) { + if (value <= 0) { + *error = true; + return NAN; + } + return log10(value); + } + *error = true; + return NAN; +} + +static char** infix_to_postfix(const char *expression, int *token_count, bool *error) { + StringStack operator_stack; + init_string_stack(&operator_stack); + char **output = malloc(MAX_STACK_SIZE * sizeof(char*)); + for (int i = 0; i < MAX_STACK_SIZE; i++) { + output[i] = malloc(MAX_TOKEN_LENGTH * sizeof(char)); + } + *token_count = 0; + *error = false; + int i = 0; + int len = strlen(expression); + while (i < len) { + if (isspace(expression[i])) { + i++; + continue; + } + if (isdigit(expression[i]) || expression[i] == '.') { + int j = 0; + char num[MAX_TOKEN_LENGTH] = {0}; + while (i < len && (isdigit(expression[i]) || expression[i] == '.')) { + num[j++] = expression[i++]; + } + num[j] = '\0'; + strcpy(output[(*token_count)++], num); + continue; + } + int func_len; + if (is_function(expression + i, &func_len)) { + char func[10] = {0}; + strncpy(func, expression + i, func_len); + func[func_len] = '\0'; + i += func_len; + push_string(&operator_stack, func); + continue; + } + if (is_operator(expression[i])) { + while (!is_string_stack_empty(&operator_stack)) { + char *top = peek_string(&operator_stack); + if (strcmp(top, "(") != 0 && + get_priority(top[0]) >= get_priority(expression[i]) && + strlen(top) == 1) { + strcpy(output[(*token_count)++], pop_string(&operator_stack)); + } else { + break; + } + } + char op[2] = {expression[i++], '\0'}; + push_string(&operator_stack, op); + continue; + } + if (expression[i] == '(') { + char bracket[2] = {expression[i++], '\0'}; + push_string(&operator_stack, bracket); + continue; + } + if (expression[i] == ')') { + i++; + while (!is_string_stack_empty(&operator_stack) && + strcmp(peek_string(&operator_stack), "(") != 0) { + strcpy(output[(*token_count)++], pop_string(&operator_stack)); + } + if (is_string_stack_empty(&operator_stack)) { + *error = true; + break; + } + pop_string(&operator_stack); + if (!is_string_stack_empty(&operator_stack)) { + char *top = peek_string(&operator_stack); + if (is_function(top, &func_len)) { + strcpy(output[(*token_count)++], pop_string(&operator_stack)); + } + } + continue; + } + *error = true; + break; + } + while (!is_string_stack_empty(&operator_stack)) { + char *top = peek_string(&operator_stack); + if (strcmp(top, "(") == 0) { + *error = true; + break; + } + strcpy(output[(*token_count)++], pop_string(&operator_stack)); + } + if (*error) { + for (int j = 0; j < MAX_STACK_SIZE; j++) { + free(output[j]); + } + free(output); + return NULL; + } + return output; +} + +static double evaluate_postfix(char **tokens, int token_count, bool *error) { + Stack value_stack; + init_stack(&value_stack); + for (int i = 0; i < token_count; i++) { + char *token = tokens[i]; + if (isdigit(token[0]) || (token[0] == '.' && isdigit(token[1]))) { + push(&value_stack, atof(token)); + continue; + } + int func_len; + if (is_function(token, &func_len)) { + if (is_stack_empty(&value_stack)) { + *error = true; + return NAN; + } + double value = pop(&value_stack); + double result = apply_function(token, value, error); + if (*error) { + return NAN; + } + push(&value_stack, result); + continue; + } + if (is_operator(token[0]) && strlen(token) == 1) { + if (is_stack_empty(&value_stack)) { + *error = true; + return NAN; + } + double b = pop(&value_stack); + if (is_stack_empty(&value_stack)) { + *error = true; + return NAN; + } + double a = pop(&value_stack); + double result = apply_operator(a, b, token[0]); + if (isnan(result)) { + *error = true; + return NAN; + } + push(&value_stack, result); + continue; + } + *error = true; + return NAN; + } + if (is_stack_empty(&value_stack)) { + *error = true; + return NAN; + } + double result = pop(&value_stack); + if (!is_stack_empty(&value_stack)) { + *error = true; + return NAN; + } + return result; +} + +double evaluate_expression(const char *expression, bool *error) { + *error = false; + if (expression == NULL || strlen(expression) == 0) { + *error = true; + return NAN; + } + int token_count; + char **postfix_tokens = infix_to_postfix(expression, &token_count, error); + if (*error || postfix_tokens == NULL) { + *error = true; + return NAN; + } + double result = evaluate_postfix(postfix_tokens, token_count, error); + for (int i = 0; i < MAX_STACK_SIZE; i++) { + free(postfix_tokens[i]); + } + free(postfix_tokens); + + return result; +} diff --git a/sk2/calculator.h b/sk2/calculator.h new file mode 100644 index 0000000..f795e9e --- /dev/null +++ b/sk2/calculator.h @@ -0,0 +1,13 @@ +#ifndef CALCULATOR_H +#define CALCULATOR_H + +#include + +double evaluate_expression(const char *expression, bool *error); +bool is_operator(char c); +int get_priority(char op); +bool is_function(const char *str, int *length); +double apply_operator(double a, double b, char op); +double apply_function(const char *func, double value, bool *error); + +#endif diff --git a/sk2/calculator.o b/sk2/calculator.o new file mode 100644 index 0000000..0b52d6c Binary files /dev/null and b/sk2/calculator.o differ diff --git a/sk2/main.c b/sk2/main.c new file mode 100644 index 0000000..cbee8cc --- /dev/null +++ b/sk2/main.c @@ -0,0 +1,41 @@ +#include "calculator.h" +#include +#include +#include +#include + +#define MAX_INPUT_LENGTH 256 + +int main() { + char input[MAX_INPUT_LENGTH]; + printf("=== Vedecka kalkulacka ===\n"); + printf("Podporovane operacie: + - * / ( )\n"); + printf("Funkcie: sin(), cos(), sqrt(), log()\n"); + printf("Mocnina: ^ (napr. 2^3 = 8)\n"); + printf("Pre ukoncenie napiste 'koniec'\n\n"); + while (1) { + printf("Zadajte vyraz: "); + if (fgets(input, sizeof(input), stdin) == NULL) { + break; + } + input[strcspn(input, "\n")] = 0; + if (strcmp(input, "koniec") == 0 || + strcmp(input, "exit") == 0 || + strcmp(input, "quit") == 0) { + break; + } + if (strlen(input) == 0) { + continue; + } + bool error = false; + double result = evaluate_expression(input, &error); + if (error || isnan(result)) { + printf("Chyba: Neplatny vyraz!\n"); + } else { + printf("Vysledok: %.2f\n", result); + } + } + + printf("Kalkulacka ukoncena.\n"); + return 0; +} diff --git a/sk2/main.o b/sk2/main.o new file mode 100644 index 0000000..e985718 Binary files /dev/null and b/sk2/main.o differ