diff --git a/Project_1.2/functions.c b/Project_1.2/functions.c index b18c0e3..d449bd9 100644 --- a/Project_1.2/functions.c +++ b/Project_1.2/functions.c @@ -64,10 +64,20 @@ R - начать поиск на другом отрезке: \n"); { case 'C': // Выбор вида "Продолжить вычисление". case 'c': + // Включение символа ECHO + term.c_lflag |= ECHO; + + // Применение новых настроек терминала + tcsetattr(0, TCSANOW, &term); return; // Выход из функции без каких-либо изменений. case 'A': // Выбор вида "Завершить вычисление". case 'a': + // Включение символа ECHO + term.c_lflag |= ECHO; + + // Применение новых настроек терминала + tcsetattr(0, TCSANOW, &term); printf("\nКорень уравнения: %lf\n", *px); printf("Работа программы завершена.\n"); exit(0); // Принудительное завершение программы с выводом текущего приближения корня. diff --git a/Project_1.2/main.c b/Project_1.2/main.c index 438878b..2fac51c 100644 --- a/Project_1.2/main.c +++ b/Project_1.2/main.c @@ -9,7 +9,6 @@ double a, b, eps, x, *pa, *pb, *px; int main() { - double tmp; pa = &a; pb = &b; diff --git a/Project_1.3/declare.h b/Project_1.3/declare.h index 9e1b174..5096fd8 100644 --- a/Project_1.3/declare.h +++ b/Project_1.3/declare.h @@ -1,5 +1,6 @@ extern double a, b, eps, x, *pa, *pb, *px; -extern short method, *mth; +extern short method, *mth, sig_flag; + // Декларирование глобальных переменных, // как внешних для последующего использования их во всей программе. #define H 0.000001 @@ -10,4 +11,5 @@ void choose_path(); void fork_method(); void chord_method(); void newton_method(); -double numerical_derivative(double x); \ No newline at end of file +double numerical_derivative(double x); +void exit_777(); \ No newline at end of file diff --git a/Project_1.3/functions.c b/Project_1.3/functions.c index 3a4dabc..366a869 100644 --- a/Project_1.3/functions.c +++ b/Project_1.3/functions.c @@ -77,6 +77,8 @@ void fork_method() // Функция поиска корней, использу void choose_path() // Функция выбора действия после вызова сигнала. { + sig_flag = 1; + char choice, *ch = &choice; struct termios term; // Задание структуры, определяющей терминал Linux. @@ -94,11 +96,10 @@ void choose_path() // Функция выбора действия после в printf("\nC - продолжить, A - закончить работу программы, \ R - начать поиск на другом отрезке, M - выбрать другой способ решения: \n"); - // Очистка стандартного потока ввода от "лишних" - __fpurge(stdin); - do { + // Очистка стандартного потока ввода от "лишних" + __fpurge(stdin); *ch = getchar(); // Запись буквы, введенной пользователем в переменную choice. switch (*ch) @@ -147,6 +148,7 @@ R - начать поиск на другом отрезке, M - выбрать return; case 'M': case 'm': + __fpurge(stdin); // Включение символа ECHO term.c_lflag |= ECHO; @@ -154,7 +156,7 @@ R - начать поиск на другом отрезке, M - выбрать tcsetattr(0, TCSANOW, &term); printf("Выберите метод вычисления корня:\ 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0)\n"); - scanf("%hd", mth); + *mth = getchar(); printf("Введите новые значения границ a и b: "); @@ -193,10 +195,16 @@ R - начать поиск на другом отрезке, M - выбрать printf("Newton\n"); newton_method(); } + else + { + printf("Fork\n"); + fork_method(); + } return; default: printf("Ошибка ввода, повторная попытка...\n"); + __fpurge(stdin); } } while (*ch != 'A' || *ch != 'R' || *ch != 'C' || *ch != 'a' || *ch != 'r' || *ch != 'c' || *ch != 'M' || *ch != 'm'); @@ -205,10 +213,15 @@ R - начать поиск на другом отрезке, M - выбрать // Применение новых настроек терминала tcsetattr(0, TCSANOW, &term); + + sig_flag = 0; } void ctrlc_handler(int signum) // Функция, заменяющая стандартный алгоритм для сигнала SIGINT. { - printf("\nТекущее приближение: %lf\n", *px); - choose_path(); + if (sig_flag == 0) + { + printf("\nТекущее приближение: %lf\n", *px); + choose_path(); + } } \ No newline at end of file diff --git a/Project_1.3/main.c b/Project_1.3/main.c index 1520639..2906229 100644 --- a/Project_1.3/main.c +++ b/Project_1.3/main.c @@ -2,16 +2,18 @@ #include #include #include +#include #include "declare.h" double a, b, eps, x, *pa, *pb, *px; -short method, *mth; +short method, *mth, sig_flag; int main() { double tmp; + sig_flag = 0; method = 0; mth = &method; pa = &a; @@ -32,9 +34,11 @@ int main() printf("Введите интервал [a, b] и точность eps: "); scanf("%lf %lf %lf", pa, pb, &eps); + + __fpurge(stdin); printf("Выберите метод вычисления корня:\ - 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0)\n"); - scanf("%hd", &method); + 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0): "); + *mth = getchar(); if (*pa > *pb) // Если пользователь перепутал границы { @@ -84,6 +88,11 @@ int main() printf("Newton\n"); newton_method(); } + else + { + printf("Fork\n"); + fork_method(); + } printf("\nКорень уравнения: %lf\n", *px); printf("Работа программы завершена.\n"); diff --git a/Project_1.3/out/function_zeros_calculator b/Project_1.3/out/function_zeros_calculator index 7cdb0c5..6a3a588 100755 Binary files a/Project_1.3/out/function_zeros_calculator and b/Project_1.3/out/function_zeros_calculator differ diff --git a/Project_test/Makefile b/Project_test/Makefile new file mode 100644 index 0000000..820099b --- /dev/null +++ b/Project_test/Makefile @@ -0,0 +1,25 @@ +# Это комментарий, который говорит, что переменная CC указывает компилятор, используемый для сборки +CC= gcc +#Это еще один комментарий. Он поясняет, что в переменной CFLAGS лежат флаги, которые передаются компилятору +CFLAGS= -c -Wall + +default: build + +general: main.o functions.o + killall -9 function_zeros_calculator + $(CC) ./out/main.o ./out/functions.o declare.h -o ./out/function_zeros_calculator -lm + + +main.o: main.c + $(CC) $(CFLAGS) main.c -o ./out/main.o + +functions.o: functions.c + $(CC) $(CFLAGS) functions.c -o ./out/functions.o + +clean: + rm -rf ./out/main.o ./out/functions.o + +build: general clean + +run: + ./out/function_zeros_calculator \ No newline at end of file diff --git a/Project_test/README b/Project_test/README new file mode 100644 index 0000000..6a1c669 --- /dev/null +++ b/Project_test/README @@ -0,0 +1,32 @@ +# Function Zeros Calculator + +## Описание +Эта программа предназначена для вычисления нулей функции на языке C в среде Linux. + +## Установка +1. Склонируйте репозиторий: git clone https://github.com/ada-dmitry/tmp_project.git +2. Перейдите в каталог проекта: cd /Project_1.2 + +## Использование +1. Соберите программу: make +2. Запустите программу: ./out/function_zeros_calculator +3. Введите необходимые параметры для вычисления нуля функции: a - ЛЕВАЯ граница отрезка + b - ПРАВАЯ граница отрезка, eps > 0 - точность вычисления корня(до 10^-6). + +## Замечания +1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень. +2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний. +3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки + вследствие переполнения памяти. + + +## Обработка сигнала SIGINT + Программа обрабатывает сигнал SIGINT, что позволяет давать пользователю выбор действия +при нажатии сочетания клавиш Ctrl+C. + +## Авторы +Антипенко Дмитрий Андреевич [C22-712] - https://github.com/ada-dmitry/ +Кузнецов Даниил Евгеньевич [C22-712] +Никитин Михаил Андреевич [C22-712] +Ускова Екатерина Александровна [C22-712] + diff --git a/Project_test/declare.h b/Project_test/declare.h new file mode 100644 index 0000000..5096fd8 --- /dev/null +++ b/Project_test/declare.h @@ -0,0 +1,15 @@ +extern double a, b, eps, x, *pa, *pb, *px; +extern short method, *mth, sig_flag; + +// Декларирование глобальных переменных, +// как внешних для последующего использования их во всей программе. +#define H 0.000001 + +double f(double x); +void ctrlc_handler(int signum); +void choose_path(); +void fork_method(); +void chord_method(); +void newton_method(); +double numerical_derivative(double x); +void exit_777(); \ No newline at end of file diff --git a/Project_test/functions.c b/Project_test/functions.c new file mode 100644 index 0000000..84a27fe --- /dev/null +++ b/Project_test/functions.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "declare.h" + +double f(double x) // Функция, заданная пользователем, для которой происходит поиск корней. +{ + return x * x * x - 125; +} + +// Приближенное вычисление производной по методу конечных разностей +double numerical_derivative(double x) +{ + return (f(x + H) - f(x)) / H; +} + +void newton_method() +{ + sig_flag = 0; + double left = *pa, right = *pb; + right = left; + do + { + printf("%lf %lf\n", left, right); + left = right; + right = left - f(left) / numerical_derivative(left); + // Используем численно вычисленную производную + *px = right; + sleep(1); + } while (fabs(right - left) > eps && f(x) != 0); + return; +} + +void chord_method() +{ + sig_flag = 0; + double left = *pa, right = *pb; + *px = left; + while ((right - left) > eps && f(x) != 0) + { + // Находим точку пересечения хорды с осью x + *px = (left * f(right) - right * f(left)) / (f(right) - f(left)); + printf("%lf %lf\n", left, right); + // Проверяем знаки функции в точках a и x + if (f(*px) == 0) + break; + else if (f(*px) * f(left) < 0) + right = *px; + else + left = *px; + sleep(1); + } + return; +} + +void fork_method() // Функция поиска корней, использующая метод вилки. +{ + sig_flag = 0; + double left = *pa, right = *pb; + do + { + *px = (left + right) / 2; // метод деления отрезка пополам + + // Печать границ для отладки и для отслеживания хода вычислений + printf("%lf %lf\n", left, right); + + // Проверка, какой из отрезков [a, x] или [x, b] подходит под условие существования корня, + // т.е. различие знаков на границе. + if (f(left) * f(x) <= 0) + right = x; + else if (f(right) * f(x) <= 0) + left = x; + + sleep(1); // Принудительное ожидание программой, для возможности прерывания пользователем. + + } while (fabs(right - left) > eps && f(x) != 0); + return; +} + +void choose_path() // Функция выбора действия после вызова сигнала. +{ + sig_flag = 1; + + char choice, *ch = &choice; + + struct termios original_term, modified_term; // Задание структуры, определяющей терминал Linux. + + tcgetattr(STDIN_FILENO, &original_term); + modified_term = original_term; + modified_term.c_lflag &= ~(ICANON | ECHO); // отключить канонического режим и отображение ввода + tcsetattr(STDIN_FILENO, TCSANOW, &modified_term); + + printf("\nПродолжить поиск корня?\n"); + printf("\nC - продолжить, A - закончить работу программы, \ +R - начать поиск на другом отрезке: \n"); + + do + { + // Очистка стандартного потока ввода от "лишних" + __fpurge(stdin); + *ch = getchar(); // Запись буквы, введенной пользователем в переменную choice. + + switch (*ch) + { + case 'C': // Выбор вида "Продолжить вычисление". + case 'c': + tcsetattr(STDIN_FILENO, TCSANOW, &original_term); + if (*mth == 0) + { + printf("Fork\n"); + fork_method(); + } + else if (*mth == 1) + { + printf("Chord\n"); + chord_method(); + } + else if (*mth == 2) + { + printf("Newton\n"); + newton_method(); + } + else + { + printf("Fork\n"); + fork_method(); + } + return; // Выход из функции без каких-либо изменений. + + case 'A': // Выбор вида "Завершить вычисление". + case 'a': + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + exit(0); // Принудительное завершение программы с выводом текущего приближения корня. + + case 'R': // Выбор вида "Продолжить вычисления с новым отрезком". + case 'r': + + tcsetattr(STDIN_FILENO, TCSANOW, &original_term); + + printf("Введите новые значения границ a и b: "); + + scanf("%lf%lf", pa, pb); + + if (f(*pa) * f(*pb) > 0) + { + printf("В указанных границах нуля функции не существует.\n"); + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + exit(0); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + return; + + default: + printf("Ошибка ввода, повторная попытка...\n"); + __fpurge(stdin); + } + } while (*ch != 'A' || *ch != 'R' || *ch != 'C' || *ch != 'a' || *ch != 'r' || *ch != 'c'); + + tcsetattr(STDIN_FILENO, TCSANOW, &original_term); + + sig_flag = 0; +} + +void ctrlc_handler(int signum) // Функция, заменяющая стандартный алгоритм для сигнала SIGINT. +{ + if (sig_flag == 0) + { + printf("\nТекущее приближение: %lf\n", *px); + choose_path(); + } +} \ No newline at end of file diff --git a/Project_test/main.c b/Project_test/main.c new file mode 100644 index 0000000..2906229 --- /dev/null +++ b/Project_test/main.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include + +#include "declare.h" + +double a, b, eps, x, *pa, *pb, *px; +short method, *mth, sig_flag; + +int main() +{ + + double tmp; + sig_flag = 0; + method = 0; + mth = &method; + pa = &a; + pb = &b; + px = &x; + + struct sigaction sig; // Инициализация структуры, отвечающей за обработку сигнала. + // Замена стандартного алгоритма на необходимый для вызова меню действий. + sig.sa_handler = ctrlc_handler; + sig.sa_flags = 0; // Очистка флагов "на всякий случай". + sigemptyset(&sig.sa_mask); // Очистка маски "на всякий случай". + + if (sigaction(SIGINT, &sig, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGINT. + { + perror("sigaction"); + return 1; + } + + printf("Введите интервал [a, b] и точность eps: "); + scanf("%lf %lf %lf", pa, pb, &eps); + + __fpurge(stdin); + printf("Выберите метод вычисления корня:\ + 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0): "); + *mth = getchar(); + + if (*pa > *pb) // Если пользователь перепутал границы + { + printf("Границы указаны неверно, запуск задачи с исправленным условием\n"); + tmp = *pa; + *pa = *pb; + *pb = tmp; + } + + if (f(*pa) * f(*pb) > 0) + { + printf("В указанных границах нуля функции не существует.\n"); + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + if (eps < 0) // Если пользователь указал отрицательную точность + { + eps = eps * (-1); + printf("Точность отрицательна, условие приведено в порядок, запуск решения...\n"); + } + + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + exit(0); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + + if (*mth == 0) + { + printf("Fork\n"); + fork_method(); + } + else if (*mth == 1) + { + printf("Chord\n"); + chord_method(); + } + else if (*mth == 2) + { + printf("Newton\n"); + newton_method(); + } + else + { + printf("Fork\n"); + fork_method(); + } + + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + + return 0; +} + +// MEEEEEEEOW \ No newline at end of file diff --git a/Project_test/out/function_zeros_calculator b/Project_test/out/function_zeros_calculator new file mode 100755 index 0000000..25ddb11 Binary files /dev/null and b/Project_test/out/function_zeros_calculator differ