diff --git a/sk2/Makefile b/sk2/Makefile new file mode 100644 index 0000000..496d7d7 --- /dev/null +++ b/sk2/Makefile @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=-Wall -lm + +all: calculator + +calculator: main.o calculator.o + $(CC) main.o calculator.o -o calculator $(CFLAGS) + +main.o: main.c calculator.h + $(CC) -c main.c + +calculator.o: calculator.c calculator.h + $(CC) -c calculator.c + +clean: + rm -f *.o calculator diff --git a/sk2/README.md b/sk2/README.md new file mode 100644 index 0000000..3260971 --- /dev/null +++ b/sk2/README.md @@ -0,0 +1,25 @@ +# Vedecká kalkulačka v jazyku C + +## Zadanie +Naprogramovať vedeckú kalkulačku, ktorá vyhodnocuje matematické výrazy +v infixnej notácii so zátvorkami a vedeckými funkciami. + +## Funkčnosť +Program podporuje: +- reálne čísla s presnosťou double +- sčítanie (+), odčítanie (-), násobenie (*), delenie (/), zátvorky +- sin, cos, odmocninu (sqrt), druhú mocninu (pow), log + +## Riešenie +Výraz je najprv prekonvertovaný z infixnej do postfixovej notácie +(Shunting-yard algoritmus). +Postfixový výraz je následne vyhodnotený pomocou zásobníka. + +## Podmienky fungovania +- prekladač GCC +- knižnica math.h + +## Použité zdroje +- Shunting Yard Algorithm - Edsger Dijkstra +- Dokumentácia jazyka C +- math.h diff --git a/sk2/calculator.c b/sk2/calculator.c new file mode 100644 index 0000000..968bcc7 --- /dev/null +++ b/sk2/calculator.c @@ -0,0 +1,122 @@ +#include "calculator.h" +#include +#include +#include +#include +#include + +#define MAX 256 +#define DEG_TO_RAD(x) ((x) * M_PI / 180.0) + +typedef struct { + double data[MAX]; + int top; +} DoubleStack; + +typedef struct { + char data[MAX][10]; + int top; +} StringStack; + +//funckie stacku +void push_double(DoubleStack *s, double v) { s->data[++s->top] = v; } +double pop_double(DoubleStack *s) { return s->data[s->top--]; } + +void push_string(StringStack *s, const char *v) { strcpy(s->data[++s->top], v); } +char *pop_string(StringStack *s) { return s->data[s->top--]; } +char *peek_string(StringStack *s) { return s->data[s->top]; } + +//priority operatorov +int priority(const char *op) { + if (!strcmp(op, "+") || !strcmp(op, "-")) return 1; + if (!strcmp(op, "*") || !strcmp(op, "/")) return 2; + if (!strcmp(op, "sin") || !strcmp(op, "cos") || + !strcmp(op, "sqrt") || !strcmp(op, "log") || + !strcmp(op, "pow")) return 3; + return 0; +} + +//infix na postfix +int infix_to_postfix(const char *infix, char postfix[][10]) { + StringStack ops = {.top = -1}; + int k = 0; + + for (int i = 0; infix[i]; ) { + if (isspace(infix[i])) { i++; continue; } + + if (isdigit(infix[i]) || infix[i] == '.') { + char num[10]; + int j = 0; + while (isdigit(infix[i]) || infix[i] == '.') + num[j++] = infix[i++]; + num[j] = '\0'; + strcpy(postfix[k++], num); + } + else if (isalpha(infix[i])) { + char func[10]; + int j = 0; + while (isalpha(infix[i])) + func[j++] = infix[i++]; + func[j] = '\0'; + push_string(&ops, func); + } + else if (infix[i] == '(') { + char t[2] = "("; + push_string(&ops, t); + i++; + } + else if (infix[i] == ')') { + while (ops.top != -1 && strcmp(peek_string(&ops), "(")) + strcpy(postfix[k++], pop_string(&ops)); + pop_string(&ops); + i++; + } + else { + char op[2] = {infix[i++], '\0'}; + while (ops.top != -1 && + priority(peek_string(&ops)) >= priority(op)) + strcpy(postfix[k++], pop_string(&ops)); + push_string(&ops, op); + } + } + + while (ops.top != -1) + strcpy(postfix[k++], pop_string(&ops)); + + return k; +} + +//vypocet postfixu +double evaluate_postfix(char postfix[][10], int n) { + DoubleStack s = {.top = -1}; + + for (int i = 0; i < n; i++) { + if (isdigit(postfix[i][0]) || postfix[i][0] == '.') { + push_double(&s, atof(postfix[i])); + } + else { + double b = pop_double(&s); + double a = (!strcmp(postfix[i], "sin") || + !strcmp(postfix[i], "cos") || + !strcmp(postfix[i], "sqrt") || + !strcmp(postfix[i], "log")) ? 0 : pop_double(&s); + + if (!strcmp(postfix[i], "+")) push_double(&s, a + b); + else if (!strcmp(postfix[i], "-")) push_double(&s, a - b); + else if (!strcmp(postfix[i], "*")) push_double(&s, a * b); + else if (!strcmp(postfix[i], "/")) push_double(&s, a / b); + else if (!strcmp(postfix[i], "sin")) push_double(&s, sin(DEG_TO_RAD(b))); + else if (!strcmp(postfix[i], "cos")) push_double(&s, cos(DEG_TO_RAD(b))); + else if (!strcmp(postfix[i], "sqrt")) push_double(&s, sqrt(b)); + else if (!strcmp(postfix[i], "log")) push_double(&s, log10(b)); + else if (!strcmp(postfix[i], "pow")) push_double(&s, pow(a, b)); + } + } + return pop_double(&s); +} + +double evaluate_expression(const char *expression) { + char postfix[MAX][10]; + int n = infix_to_postfix(expression, postfix); + return evaluate_postfix(postfix, n); +} diff --git a/sk2/calculator.h b/sk2/calculator.h new file mode 100644 index 0000000..0aad8eb --- /dev/null +++ b/sk2/calculator.h @@ -0,0 +1,6 @@ +#ifndef CALCULATOR_H +#define CALCULATOR_H + +double evaluate_expression(const char *expression); + +#endif diff --git a/sk2/main.c b/sk2/main.c new file mode 100644 index 0000000..05da9ca --- /dev/null +++ b/sk2/main.c @@ -0,0 +1,14 @@ +#include +#include "calculator.h" + +int main() { + char expr[256]; + + printf("Zadaj vyraz: "); + fgets(expr, sizeof(expr), stdin); + + double result = evaluate_expression(expr); + printf("Vysledok: %.2f\n", result); + + return 0; +}