diff --git a/du3/program.c b/du3/program.c index b888cea..92d9eee 100644 --- a/du3/program.c +++ b/du3/program.c @@ -1,264 +1,112 @@ #include #include #include -#include -#include -#define EPSILON 0.001 // Tolerancia pre porovnanie reálnych čísel: ak je rozdiel menší alebo rovný EPSILON, považujeme čísla za rovnaké. +#define EPSILON 0.001 +#define BUFFER_SIZE 100 -/* - * Funkcia trim_newline - * -------------------- - * Odstraňuje znak nového riadku ('\n') zo zadaného reťazca, ak je prítomný. - * Pri načítavaní riadkov pomocou fgets sa totiž často na konci reťazca nachádza '\n', - * ktorý by mohol ovplyvniť ďalšie spracovanie. - * - * Parametre: - * - line: Reťazec, z ktorého sa má odstrániť koncový znak nového riadku. - */ -void trim_newline(char *line) { - size_t len = strlen(line); - if (len > 0 && line[len - 1] == '\n') { - line[len - 1] = '\0'; - } -} - -/* - * Funkcia skip_spaces - * -------------------- - * Preskakuje všetky whitespace znaky (medzery, tabulátory, nové riadky) v zadanom reťazci - * a vráti ukazovateľ na prvý znak, ktorý nie je whitespace. - * - * Parametre: - * - str: Reťazec, v ktorom chceme preskočiť medzery. - * - * Návratová hodnota: - * - Ukazovateľ na prvý znak, ktorý nie je whitespace. - */ -char* skip_spaces(char *str) { - while (*str && isspace((unsigned char)*str)) { - str++; - } - return str; -} - -/* - * Funkcia parse_expression - * ------------------------- - * Rozparsuje riadok obsahujúci matematický príklad vo formáte: - * - * ČÍSLO OPERÁCIA ČÍSLO = VÝSLEDOK - * - * Medzi jednotlivými časťami môže byť ľubovoľný počet medzier. - * - * Parametre: - * - line: Reťazec obsahujúci matematický príklad, napr. "1.1 + 2.2 = 3.3" - * - num1: Ukazovateľ, do ktorého sa uloží prvé číslo. - * - op: Ukazovateľ, do ktorého sa uloží operátor ('+', '-', '*' alebo '/'). - * - num2: Ukazovateľ, do ktorého sa uloží druhé číslo. - * - result: Ukazovateľ, do ktorého sa uloží očakávaný výsledok. - * - * Návratová hodnota: - * - 0, ak sa parsovanie podarilo úspešne. - * - 1, ak nastala chyba (nesprávny formát, chýbajúce číslo, operátor alebo '=') - * - * Príklad vstupu: - * " 10.0 / 2.0 = 5.0" - */ -int parse_expression(char *line, float *num1, char *op, float *num2, float *result) { - char *ptr = line; - - // Preskočíme úvodné medzery a načítame prvé číslo - ptr = skip_spaces(ptr); - char *endPtr; - *num1 = strtof(ptr, &endPtr); - if (ptr == endPtr) { - return 1; // Chyba: nepodarilo sa načítať číslo - } - ptr = endPtr; - - // Preskočíme medzery a načítame operátor - ptr = skip_spaces(ptr); - if (*ptr == '\0') return 1; - *op = *ptr; - if (*op != '+' && *op != '-' && *op != '*' && *op != '/') { - return 1; // Chyba: operátor nie je platný - } - ptr++; - - // Preskočíme medzery a načítame druhé číslo - ptr = skip_spaces(ptr); - *num2 = strtof(ptr, &endPtr); - if (ptr == endPtr) { - return 1; // Chyba: nepodarilo sa načítať druhé číslo - } - ptr = endPtr; - - // Preskočíme medzery a očakávame znak '=' - ptr = skip_spaces(ptr); - if (*ptr != '=') { - return 1; // Chyba: chýba znak '=' - } - ptr++; // Preskočíme '=' - - // Preskočíme medzery a načítame výsledok - ptr = skip_spaces(ptr); - *result = strtof(ptr, &endPtr); - if (ptr == endPtr) { - return 1; // Chyba: nepodarilo sa načítať výsledok - } - ptr = endPtr; - - // Overíme, že za výsledkom nie sú žiadne neočakávané znaky (okrem medzier) - ptr = skip_spaces(ptr); - if (*ptr != '\0') { - return 1; // Chyba: neočakávané znaky za výsledkom - } - - return 0; // Úspešné parsovanie -} - -/* - * Funkcia calculate - * ----------------- - * Vykoná aritmetickú operáciu medzi dvoma číslami podľa zadaného operátora. - * - * Parametre: - * - num1: Prvé číslo. - * - op: Operátor ('+', '-', '*' alebo '/'). - * - num2: Druhé číslo. - * - error: Ukazovateľ, do ktorého sa uloží 1, ak nastane chyba (napr. delenie nulou). - * - * Návratová hodnota: - * - Výsledok operácie, ak prebehne úspešne. - * - Ak nastane chyba, error je nastavený na 1 a funkcia vráti 0. - * - * Príklad: - * calculate(10.0, '/', 2.0, &error) vráti 5.0, error zostáva 0. - */ -float calculate(float num1, char op, float num2, int *error) { - *error = 0; // Inicializácia chyby na 0 (žiadna chyba) - float res; - switch(op) { - case '+': - res = num1 + num2; - break; - case '-': - res = num1 - num2; - break; - case '*': - res = num1 * num2; - break; - case '/': - // Kontrola delenia nulou; ak num2 je takmer 0, signalizujeme chybu - if (fabs(num2) < EPSILON) { - *error = 1; // Chyba: delenie nulou - return 0; - } - res = num1 / num2; - break; - default: - *error = 1; +// Функция вычисления результата +float vypocitaj(float a, float b, char op, int* error) { + if (op == '+') return a + b; + if (op == '-') return a - b; + if (op == '*') return a * b; + if (op == '/') { + if (b == 0) { + *error = 1; // Ошибка: деление на ноль return 0; + } + return a / b; } - return res; + *error = 1; // Ошибка: некорректный оператор + return 0; } -/* - * Funkcia process_line - * --------------------- - * Spracuje jeden riadok vstupu obsahujúci matematický príklad a určí, či je zápis - * správny a či je výsledok správny. - * - * Postup: - * 1. Skopíruje vstupný riadok do lokálneho bufferu a odstráni prípadný koncový znak nového riadku. - * 2. Rozparsuje riadok na časti: prvé číslo, operátor, druhé číslo a očakávaný výsledok. - * 3. Ak parsovanie zlyhá, nastaví output na "CHYBA". - * 4. Vykoná operáciu a ak nastane chyba (napr. delenie nulou), nastaví output na "ZLE". - * 5. Zaokrúhli výsledok operácie na 2 desatinné miesta, pretože čísla sú zadané na max. 2 desatinné miesta. - * 6. Porovná zaokrúhlený výsledok s očakávaným výsledkom. Ak sa líšia o viac ako EPSILON, - * nastaví output na "ZLE", inak na "OK". - * - * Parametre: - * - line: Vstupný riadok (napr. "10.0 / 2.0 = 5.0"). - * - output: Buffer, do ktorého sa uloží výsledný reťazec ("OK", "ZLE" alebo "CHYBA"). - * - output_size: Veľkosť bufferu output. - * - * Príklad vstupu a výstupu: - * Vstup: "1 + 1 = 2" - * Výstup: "OK" - */ -void process_line(const char *line, char *output, size_t output_size) { - char buffer[256]; - // Skopírujeme vstupný riadok do lokálneho bufferu - strncpy(buffer, line, 255); - buffer[255] = '\0'; // Zabezpečíme, že buffer je správne zakončený '\0' - trim_newline(buffer); - - float num1, num2, givenResult; - char op; - // Pokúsime sa rozparsovať matematický príklad - if (parse_expression(buffer, &num1, &op, &num2, &givenResult) != 0) { - snprintf(output, output_size, "CHYBA"); - return; - } - - int calcError = 0; - float calculatedResult = calculate(num1, op, num2, &calcError); - if (calcError) { - // V prípade chyby (napr. delenie nulou) vypíšeme "ZLE" - snprintf(output, output_size, "ZLE"); - return; - } - - // Zaokrúhľujeme výsledok operácie na 2 desatinné miesta, pretože vstupné čísla majú max. 2 desatinné miesta. - float roundedResult = round(calculatedResult * 100) / 100; - - // Porovnáme zaokrúhlený výsledok so zadaným výsledkom. - if (fabs(roundedResult - givenResult) <= EPSILON) { - snprintf(output, output_size, "OK"); +// Функция проверки результата +void over_vysledok(float skutocny, float ocakavany) { + if (abs(skutocny - ocakavany) <= EPSILON) { + printf("OK\n"); } else { - snprintf(output, output_size, "ZLE"); + printf("ZLE\n"); } } -/* - * Hlavná funkcia programu. - * ------------------------- - * Program načíta riadky zo štandardného vstupu. Každý riadok obsahuje matematický príklad vo formáte: - * - * ČÍSLO OPERÁCIA ČÍSLO = VÝSLEDOK - * - * Príklad vstupu: - * 10.0 / 2.0 = 5.0 - * 1+2=3 - * 3.333+4.667=8.0 - * - * Pre každý neprázdny riadok program overí správnosť zápisu a výsledku a na štandardný výstup - * vypíše "OK", "ZLE" alebo "CHYBA". - * - * Ak sa načíta prázdny riadok (iba medzery), program sa ukončí. - * - * Ako skompilovať: - * gcc program.c -o program -lm - * - * Ako spustiť: - * ./program - */ -int main(int argc, char *argv[]) { - char buffer[256]; - char output[32]; +// Функция обработки одной строки +void spracuj_riadok(char* riadok) { + char* zaciatok = riadok; + char* koniec; - // Načítavame riadky zo štandardného vstupu (napr. z konzoly alebo súboru) - while (fgets(buffer, sizeof(buffer), stdin) != NULL) { - trim_newline(buffer); - // Ak je riadok prázdny (iba medzery), ukončíme cyklus a program - if (*skip_spaces(buffer) == '\0') { + // Читаем первое число + float a = strtof(zaciatok, &koniec); + if (zaciatok == koniec) { + printf("CHYBA\n"); + return; + } + + // Пропускаем пробелы перед оператором + while (*koniec == ' ') koniec++; + + // Читаем оператор + char op = *koniec; + if (op != '+' && op != '-' && op != '*' && op != '/') { + printf("CHYBA\n"); + return; + } + + // Двигаем указатель дальше + koniec++; + while (*koniec == ' ') koniec++; + + // Читаем второе число + float b = strtof(koniec, &koniec); + if (koniec == zaciatok) { + printf("CHYBA\n"); + return; + } + + // Пропускаем пробелы перед знаком "=" + while (*koniec == ' ') koniec++; + if (*koniec != '=') { + printf("CHYBA\n"); + return; + } + + // Двигаем указатель дальше + koniec++; + while (*koniec == ' ') koniec++; + + // Читаем результат + float vysledok = strtof(koniec, &koniec); + if (koniec == zaciatok) { + printf("CHYBA\n"); + return; + } + + // Вычисляем реальный результат + int error = 0; + float skutocny = vypocitaj(a, b, op, &error); + if (error) { + printf("CHYBA\n"); + return; + } + + // Проверяем правильность ответа + over_vysledok(skutocny, vysledok); +} + +int main() { + char buffer[BUFFER_SIZE]; + + while (1) { + printf("Zadajte priklad:\n"); + + if (!fgets(buffer, sizeof(buffer), stdin)) break; // Проверяем конец ввода + if (buffer[0] == '\n') { + printf("KONIEC\n"); break; } - process_line(buffer, output, sizeof(output)); - printf("%s\n", output); + + spracuj_riadok(buffer); } - + return 0; } \ No newline at end of file