funguje
This commit is contained in:
parent
44e8945215
commit
16b668dd27
22
sk2/Makefile
Normal file
22
sk2/Makefile
Normal file
@ -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
|
||||||
55
sk2/README.md
Normal file
55
sk2/README.md
Normal file
@ -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
|
||||||
BIN
sk2/calculator
Executable file
BIN
sk2/calculator
Executable file
Binary file not shown.
328
sk2/calculator.c
Normal file
328
sk2/calculator.c
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
#include "calculator.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
13
sk2/calculator.h
Normal file
13
sk2/calculator.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef CALCULATOR_H
|
||||||
|
#define CALCULATOR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
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
|
||||||
BIN
sk2/calculator.o
Normal file
BIN
sk2/calculator.o
Normal file
Binary file not shown.
41
sk2/main.c
Normal file
41
sk2/main.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "calculator.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
BIN
sk2/main.o
Normal file
BIN
sk2/main.o
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user