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