diff --git a/project/ada_712.tar b/project/ada_712.tar index 78eed57..d5e23ed 100644 Binary files a/project/ada_712.tar and b/project/ada_712.tar differ diff --git a/test/ver1.6/Makefile b/project/ada_712/Makefile similarity index 100% rename from test/ver1.6/Makefile rename to project/ada_712/Makefile diff --git a/test/ver1.6/README.md b/project/ada_712/README.md similarity index 100% rename from test/ver1.6/README.md rename to project/ada_712/README.md diff --git a/test/ver1.6/declare.h b/project/ada_712/declare.h similarity index 100% rename from test/ver1.6/declare.h rename to project/ada_712/declare.h diff --git a/test/ver1.6/functions.c b/project/ada_712/functions.c similarity index 100% rename from test/ver1.6/functions.c rename to project/ada_712/functions.c diff --git a/test/ver1.6/main.c b/project/ada_712/main.c similarity index 100% rename from test/ver1.6/main.c rename to project/ada_712/main.c diff --git a/project/ver1.6/Makefile b/project/ver1.6/Makefile new file mode 100644 index 0000000..69c7793 --- /dev/null +++ b/project/ver1.6/Makefile @@ -0,0 +1,18 @@ +# Это комментарий, который говорит, что переменная CC указывает компилятор, используемый для сборки +CC=gcc +#Это еще один комментарий. Он поясняет, что в переменной CFLAGS лежат флаги, которые передаются компилятору +CFLAGS=-Wall -pedantic + +default: build + +clean: + rm ./out/func_zero_calc + + +build: + $(CC) ./main.c ./functions.c $(CFLAGS) -o ./out/func_zero_calc -lm + +run: + ./out/func_zero_calc + + \ No newline at end of file diff --git a/project/ver1.6/README.md b/project/ver1.6/README.md new file mode 100644 index 0000000..7d70136 --- /dev/null +++ b/project/ver1.6/README.md @@ -0,0 +1,56 @@ +# func_zero_calc + +## Описание + +Эта программа предназначена для вычисления нулей функции на языке C в среде Linux. + +## Установка (с помощью репозитория на GitHub) + +1. Склонируйте репозиторий: git clone https://github.com/ada-dmitry/tmp_project.git +2. Перейдите в директорию проекта: cd /done_project +3. Следуйте указаниям пункта "Использование" + +## Установка (с помощью архива .tar) + +1. Распакуйте архив в любую удобную вам директорию. +2. С помощью терминала зайдите в распакованную директорию по заданному пути. +3. Следуйте указаниям пункта "Использование" + +## Использование + +0. Для нормальной работы программы необходимо установить программу GNU PLot и сборщик make + (sudo apt install gnuplot || sudo apt install make) +1. Соберите программу: make +2. Запустите программу: make run +3. Строго следуйте указаниям программы, вводя границы отрезка, точность вычисления корня и + выбирая метод вычисления. + +## Замечания + +0. В поля ввода границ и точности необходимо соблюдать несколько ограничений: + а. Вводить числа(без использования иных символов, помимо знака отрицания в начале "-" или дробной точки ".") + б. Не выходить за пределы типа double(1,7E–308 до 1,7E+308) +1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень + (это можно проверить благодаря графику). +2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний. +3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки + вследствие переполнения памяти. + +## Обработка сигнала SIGINT + + Программа обрабатывает сигнал SIGINT, что позволяет давать пользователю выбор действия + +при нажатии сочетания клавиш Ctrl+C. + +## Обработка сигнала SIGTSTP + + Программа обрабатывает сигнал SIGTSTP, переводящий программу в фоновый режим, + +вновь предоставляя пользователю управлять терминалом, но возвращающий настройки терминала к исходным. + +## Авторы + +Антипенко Дмитрий Андреевич [C22-712] - https://github.com/ada-dmitry/ +Кузнецов Даниил Евгеньевич [C22-712] +Никитин Михаил Андреевич [C22-712] +Ускова Екатерина Александровна [C22-712] diff --git a/project/ver1.6/declare.h b/project/ver1.6/declare.h new file mode 100644 index 0000000..3d7cd2b --- /dev/null +++ b/project/ver1.6/declare.h @@ -0,0 +1,30 @@ +#include + +extern double a, b, eps, x, *pa, *pb, *px; +extern short method, *mth, sig_flag; +extern struct termios default_term, modif_term; +// Декларирование глобальных переменных, +// как внешних для последующего использования их во всей программе. +#define H 0.000001 +#define A -10000 +#define B 10000 +#define EPS 0.001 + +double f(double x); +void ctrlc_handler(int signum); +void ctrlz_handler(int signum); +void choose_path(); +void fork_method(); +void chord_method(); +void newton_method(); +double numerical_derivative(double x); +void __exit(); +void show_grapgh(); +void input_diap(); +void change_diap(); +// double input_number(char ch); +bool is_digit(char c); +bool is_sign(char c); +bool is_dot(char c); +double read_parse(char ch); +bool is_enter(char c); \ No newline at end of file diff --git a/project/ver1.6/functions.c b/project/ver1.6/functions.c new file mode 100644 index 0000000..65d501d --- /dev/null +++ b/project/ver1.6/functions.c @@ -0,0 +1,363 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "declare.h" + +double f(double x) // Функция, заданная пользователем, для которой происходит поиск корней. +{ + return x - 20; +} + +void show_grapgh() +{ + char func[100] = "x-20"; + // Подключение GNU Plot + FILE *gp = popen("gnuplot -persist", "w"); + + if (gp == NULL) + { + printf("GNUerror\n"); + exit(3); + } + fprintf(gp, "set xrange [-5000:5000]\n"); + fprintf(gp, "set yrange [-5000:5000]\n"); + fprintf(gp, "set grid\n"); + fprintf(gp, "plot %s\n", func); + fflush(gp); // очищение буфера вывода + sig_flag = 1; + printf("Вернитесь в терминал и нажмите Enter, чтобы продолжить...\n"); + getchar(); + sig_flag = 0; + fprintf(gp, "exit\n"); + return; +} + +// Приближенное вычисление производной по методу конечных разностей +double numerical_derivative(double x) +{ + return (f(x + H) - f(x)) / H; +} + +void newton_method() +{ + *pb = *pa; + do + { + printf("%lf %lf\n", *pa, *pb); + *pa = *pb; + *pb = *pa - f(*pa) / numerical_derivative(*pa); + // Используем численно вычисленную производную + *px = *pb; + sleep(1); + } while (fabs(*pb - *pa) > eps && f(x) != 0); + return; +} + +void chord_method() +{ + *px = *pa; + while ((*pb - *pa) > eps && f(x) != 0) + { + // Находим точку пересечения хорды с осью x + *px = (*pa * f(*pb) - *pb * f(*pa)) / (f(*pb) - f(*pa)); + printf("%lf %lf\n", *pa, *pb); + // Проверяем знаки функции в точках a и x + if (f(*px) == 0) + break; + else if (f(*px) * f(*pa) < 0) + *pb = *px; + else + *pa = *px; + sleep(1); + } + return; +} + +void fork_method() // Функция поиска корней, использующая метод вилки. +{ + do + { + *px = (*pa + *pb) / 2; // метод деления отрезка пополам + + // Печать границ для отладки и для отслеживания хода вычислений + printf("%lf %lf\n", *pa, *pb); + + // Проверка, какой из отрезков [a, x] или [x, b] подходит под условие существования корня, + // т.е. различие знаков на границе. + + if (f(*pa) * f(x) <= 0) + *pb = x; + else if (f(*pb) * f(x) <= 0) + *pa = x; + + sleep(1); // Принудительное ожидание программой, для возможности прерывания пользователем. + + } while (fabs(*pb - *pa) > eps && f(x) != 0); + return; +} + +void choose_path() // Функция выбора действия после вызова сигнала. +{ + sig_flag = 1; + char choice; + tcsetattr(0, TCSANOW, &modif_term); + + printf("\nПродолжить поиск корня?\n"); + printf("\nC - продолжить, A - закончить работу программы, \ +R - начать поиск на другом отрезке: \n"); + + do + { + // Очистка стандартного потока ввода от "лишних" + __fpurge(stdin); + choice = getchar(); + + switch (choice) + { + case 'C': // Выбор вида "Продолжить вычисление". + case 'c': + sig_flag = 0; + system("clear"); + return; // Выход из функции без каких-либо изменений. + + case 'A': // Выбор вида "Завершить вычисление". + case 'a': + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + __exit(); // Принудительное завершение программы с выводом текущего приближения корня. + + case 'R': // Выбор вида "Продолжить вычисления с новым отрезком". + case 'r': + change_diap(); + return; + + default: + system("clear"); + printf("Ошибка ввода, повторная попытка...\n"); + __fpurge(stdin); + } + } while (choice != 'A' || choice != 'R' || choice != 'C' || choice != 'a' || choice != 'r' || choice != 'c' || choice != 'M' || choice != 'm'); + + // Применение новых настроек терминала + tcsetattr(0, TCSANOW, &default_term); + + sig_flag = 0; +} + +void ctrlc_handler(int signum) // Функция, заменяющая стандартный алгоритм для сигнала SIGINT. +{ + if (sig_flag == 0) + { + system("clear"); + printf("\nТекущее приближение: %lf\n", *px); + choose_path(); + } + return; +} + +void ctrlz_handler(int signum) +{ + kill(getpid(), SIGTSTP); // Отправляем сигнал SIGTSTP процессу + tcsetattr(STDIN_FILENO, TCSANOW, &default_term); + return; +} + +void __exit() +{ + tcsetattr(0, TCSANOW, &default_term); // Применение новых настроек терминала + exit(EXIT_SUCCESS); +} + +void input_diap() +{ + double tmp; + sig_flag = 1; + + system("clear"); + printf("\n\nТекущие значения: [%g] : %g | eps = %g\n\n\ +Введите левую границу отрезка и нажмите Enter (по умолчанию: %g): ", + *pa, *pb, eps, *pa); + + *pa = read_parse('A'); + + system("clear"); + printf("\nТекущие значения: %g : [%g] | eps = %g\n\n\ +Введите правую границу отрезка и нажмите Enter (по умолчанию: %g): ", + *pa, *pb, eps, *pb); + + *pb = read_parse('B'); + + system("clear"); + printf("\nТекущие значения: %g : %g | eps = [%g]\n\n\ +Введите точность вычисления и нажмите Enter (по умолчанию: %g): ", + *pa, *pb, eps, eps); + + eps = read_parse('E'); + + system("clear"); + __fpurge(stdin); + printf("\nВыберите метод вычисления корня и нажмите Enter:\ + 0 - метод вилки, 1 - метод хорд, 2 - метод касательных\n(По умолчанию: 0): "); + *mth = getchar(); + + if (*pa > *pb) // Если пользователь перепутал границы + { + printf("Границы указаны неверно, запуск задачи с исправленным условием\n"); + tmp = *pa; + *pa = *pb; + *pb = tmp; + } + + if (f(*pa) * f(*pb) > 0) + { + sig_flag = 0; + printf("В указанных границах нуля функции не существует.\n"); + printf("Поменяйте границы\n"); + change_diap(); + } + if (eps < 0) // Если пользователь указал отрицательную точность + { + eps = eps * (-1); + printf("Точность отрицательна, условие приведено в порядок, запуск решения...\n"); + } + + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + __exit(); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + sig_flag = 0; + return; +} + +void change_diap() +{ + // Возврат к обычному выводу + tcsetattr(0, TCSANOW, &default_term); + + system("clear"); + + printf("Введите новое значение левой границы: "); + *pa = read_parse('A'); + printf("Введите новое значение правой границы: "); + *pb = read_parse('B'); + + if (f(*pa) * f(*pb) > 0) + { + printf("\nВ указанных границах нуля функции не существует.\n"); + printf("Поменяйте границы\n"); + choose_path(); + } + if (*pa == *pb) + { + if (f(*pa) == 0) + { + printf("\nКорень уравнения: %lf\n", *pa); + printf("Работа программы завершена.\n"); + __exit(); + } + else + { + printf("Нажмите Ctrl+C и поменяйте границы\n"); + } + } + + sig_flag = 0; + return; +} + +bool is_digit(char c) +{ + return (c >= '0' && c <= '9'); +} + +bool is_sign(char c) +{ + return (c == '+' || c == '-'); +} + +bool is_dot(char c) +{ + return (c == '.'); +} + +bool is_enter(char c) +{ + return (c == '\n'); +} + +double read_parse(char ch) +{ + char input[50]; + double number; + fgets(input, sizeof(input), stdin); + __fpurge(stdin); + + int i = 0; + bool is_valid = true; + bool has_dot = false; + // Проверка первого символа, который может быть знаком или переносом строки + if (is_sign(input[0])) + { + i++; + } + else if (is_enter(input[0])) + { + switch (ch) + { + case 'A': + return A; + case 'B': + return B; + case 'E': + return EPS; + } + } + // Проверка символов, формирующих цифры числа + while (input[i] != '\n') + { + if (is_digit(input[i])) + { + i++; + continue; + } + else if (is_dot(input[i]) && !has_dot) + { + has_dot = true; + i++; + continue; + } + else + { + is_valid = false; + break; + } + } + + if (is_valid) + { + number = atof(input); + return number; + } + else + { + printf("Ошибка: некорректный ввод\nЗавершение выполнения программы...\n"); + __exit(); + } + return 1; +} diff --git a/project/ver1.6/main.c b/project/ver1.6/main.c new file mode 100644 index 0000000..5baf7f3 --- /dev/null +++ b/project/ver1.6/main.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include + +#include "declare.h" + +double a, b, eps, x, *pa, *pb, *px; +short method, *mth, sig_flag; +struct termios default_term, modif_term; // Задание структур, определяющих терминал Linux. + +int main() +{ + tcgetattr(0, &default_term); // Получение текущих настроек терминала + modif_term = default_term; + modif_term.c_lflag &= ~(ECHO | ICANON); // Отключение символа ECHO и канонического ввода + + sig_flag = 0; + method = 0; + mth = &method; + a = A; + b = B; + eps = EPS; + pa = &a; + pb = &b; + px = &x; + + struct sigaction sig_int, sig_tstp; // Инициализация структуры, отвечающей за обработку сигнала. + // Замена стандартного алгоритма на необходимый для вызова меню действий. + sig_int.sa_handler = ctrlc_handler; + sig_int.sa_flags = 0; // Очистка флагов "на всякий случай". + sigemptyset(&sig_int.sa_mask); // Очистка маски "на всякий случай". + sig_tstp.sa_handler = ctrlz_handler; + sig_tstp.sa_flags = 0; + sigemptyset(&sig_tstp.sa_mask); + + if (sigaction(SIGINT, &sig_int, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGINT. + { + perror("sigaction"); + return 1; + } + if (sigaction(SIGTSTP, &sig_tstp, NULL) == -1) // Обработчик ошибок и инициализация сигнала SIGTSTP. + { + perror("sigaction"); + return 1; + } + + show_grapgh(); + input_diap(); + + system("clear"); + if (*mth == 0) + { + printf("\nFork\n"); + fork_method(); + } + else if (*mth == 1) + { + printf("\nChord\n"); + chord_method(); + } + else if (*mth == 2) + { + printf("\nNewton\n"); + newton_method(); + } + else + { + printf("\nFork\n"); + fork_method(); + } + + printf("\nКорень уравнения: %lf\n", *px); + printf("Работа программы завершена.\n"); + + return 0; +} diff --git a/test/ver1.6/out/func_zero_calc b/project/ver1.6/out/func_zero_calc similarity index 100% rename from test/ver1.6/out/func_zero_calc rename to project/ver1.6/out/func_zero_calc diff --git a/test/ver1.6/out/function_zeros_calculator b/project/ver1.6/out/function_zeros_calculator similarity index 100% rename from test/ver1.6/out/function_zeros_calculator rename to project/ver1.6/out/function_zeros_calculator