added 1.6

This commit is contained in:
ada-dmitry
2023-12-21 11:44:34 +03:00
parent 5bbe9fdf26
commit e405b960a7
16 changed files with 568 additions and 22 deletions
+2
View File
@@ -1,3 +1,5 @@
1.4 Добавлен вывод графиков функций, добавлена проприетарная функция выхода с возвратом значений настроек системы по умолчанию. 1.4 Добавлен вывод графиков функций, добавлена проприетарная функция выхода с возвратом значений настроек системы по умолчанию.
1.5 Добавлен второй обработчик сигналов для комбинации Ctrl+Z - переход в exit_777(выход из программы с возвратом настроек по умолчанию.) 1.5 Добавлен второй обработчик сигналов для комбинации Ctrl+Z - переход в exit_777(выход из программы с возвратом настроек по умолчанию.)
1.6 Обработчик Ctrl+Z включен в работу, настройки терминала вынесены в глобальную переменную
-1
View File
@@ -6,7 +6,6 @@ CFLAGS= -c -Wall
default: build default: build
general: main.o functions.o general: main.o functions.o
killall -9 function_zeros_calculator
$(CC) ./out/main.o ./out/functions.o -o ./out/function_zeros_calculator -lm $(CC) ./out/main.o ./out/functions.o -o ./out/function_zeros_calculator -lm
main.o: main.c main.o: main.c
+12 -7
View File
@@ -1,35 +1,40 @@
# Function Zeros Calculator # Function Zeros Calculator
## Описание ## Описание
Эта программа предназначена для вычисления нулей функции на языке C в среде Linux. Эта программа предназначена для вычисления нулей функции на языке C в среде Linux.
## Установка ## Установка
1. Склонируйте репозиторий: git clone https://github.com/ada-dmitry/tmp_project.git 1. Склонируйте репозиторий: git clone https://github.com/ada-dmitry/tmp_project.git
2. Перейдите в каталог проекта: cd /Project_1.2 2. Перейдите в каталог проекта: cd /Project_1.2
## Использование ## Использование
0. Для нормальной работы программы необходимо установить программу GNU PLot
(sudo apt install gnuplot) 0. Для нормальной работы программы необходимо установить программу GNU PLot
(sudo apt install gnuplot)
1. Соберите программу: make 1. Соберите программу: make
2. Запустите программу: ./out/function_zeros_calculator 2. Запустите программу: ./out/function_zeros_calculator
3. Введите необходимые параметры для вычисления нуля функции: a - ЛЕВАЯ граница отрезка 3. Введите необходимые параметры для вычисления нуля функции: a - ЛЕВАЯ граница отрезка
b - ПРАВАЯ граница отрезка, eps > 0 - точность вычисления корня(до 10^-6). b - ПРАВАЯ граница отрезка, eps > 0 - точность вычисления корня(до 10^-6).
## Замечания ## Замечания
1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень 1. Для корректной работы программы, необходимо вводить отрезок, на котором есть лишь один корень
(это можно проверить благодаря графику). (это можно проверить благодаря графику).
2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний. 2. После вызова меню выбора действий (Ctrl+C) можно использовать как верхний регистр, так и нижний.
3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки 3. Не рекомендуется бесконечно вызывать Ctrl+C без выбора действия, это может повлечь ошибки
вследствие переполнения памяти. вследствие переполнения памяти.
## Обработка сигнала SIGINT ## Обработка сигнала SIGINT
Программа обрабатывает сигнал SIGINT, что позволяет давать пользователю выбор действия Программа обрабатывает сигнал SIGINT, что позволяет давать пользователю выбор действия
при нажатии сочетания клавиш Ctrl+C. при нажатии сочетания клавиш Ctrl+C.
## Авторы ## Авторы
Антипенко Дмитрий Андреевич [C22-712] - https://github.com/ada-dmitry/ Антипенко Дмитрий Андреевич [C22-712] - https://github.com/ada-dmitry/
Кузнецов Даниил Евгеньевич [C22-712] Кузнецов Даниил Евгеньевич [C22-712]
Никитин Михаил Андреевич [C22-712] Никитин Михаил Андреевич [C22-712]
Ускова Екатерина Александровна [C22-712] Ускова Екатерина Александровна [C22-712]
+10 -1
View File
@@ -2,7 +2,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <math.h> #include <math.h>
// #include <signal.h>
#include <termios.h> #include <termios.h>
#include <stdio_ext.h> #include <stdio_ext.h>
@@ -114,6 +113,7 @@ void choose_path() // Функция выбора действия после в
sig_flag = 1; sig_flag = 1;
char choice; char choice;
double tmp;
struct termios default_term, modif_term; // Задание структуры, определяющей терминал Linux. struct termios default_term, modif_term; // Задание структуры, определяющей терминал Linux.
@@ -140,6 +140,7 @@ R - начать поиск на другом отрезке: \n");
case 'C': // Выбор вида "Продолжить вычисление". case 'C': // Выбор вида "Продолжить вычисление".
case 'c': case 'c':
sig_flag = 0; sig_flag = 0;
tcsetattr(0, TCSANOW, &default_term);
return; // Выход из функции без каких-либо изменений. return; // Выход из функции без каких-либо изменений.
case 'A': // Выбор вида "Завершить вычисление". case 'A': // Выбор вида "Завершить вычисление".
@@ -157,6 +158,14 @@ R - начать поиск на другом отрезке: \n");
scanf("%lf%lf", pa, pb); scanf("%lf%lf", pa, pb);
if (*pa > *pb) // Если пользователь перепутал границы
{
printf("Границы указаны неверно, запуск задачи с исправленным условием\n");
tmp = *pa;
*pa = *pb;
*pb = tmp;
}
if (f(*pa) * f(*pb) > 0) if (f(*pa) * f(*pb) > 0)
{ {
printf("\nВ указанных границах нуля функции не существует.\n"); printf("\nВ указанных границах нуля функции не существует.\n");
Binary file not shown.
+48
View File
@@ -0,0 +1,48 @@
/*
* $gcc -Wall main.c -o main -ldl
* $./main sin\(x\) 1.62
* 0.998790
* $./main sin\(x\)*exp\(x\) 1.62
* 5.046975
*/
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#define BEGIN "#include <math.h>\ndouble func(double x){\nreturn "
#define END ";\n}\n"
#define MAKELIB "gcc -c -Wall func.c -o func.o && gcc -L. -shared func.o -o libfunc.so -lm"
int main(int argc, char *argv[])
{
void *handle;
double (*fun)(double);
char *error;
FILE *f;
f = fopen("func.c", "w");
fprintf(f, "%s%s%s", BEGIN, argv[1], END);
fclose(f);
system(MAKELIB);
handle = dlopen("./libfunc.so", RTLD_LAZY);
if (!handle)
{
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror();
fun = (double (*)(double))dlsym(handle, "func");
error = dlerror();
if (error != NULL)
{
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("%f\n", (*fun)(atof(argv[2])));
dlclose(handle);
exit(EXIT_SUCCESS);
}
+24 -12
View File
@@ -22,25 +22,37 @@ void show_grapgh()
new_term.c_lflag &= ~(ECHO | ICANON); new_term.c_lflag &= ~(ECHO | ICANON);
tcsetattr(STDIN_FILENO, TCSANOW, &new_term); tcsetattr(STDIN_FILENO, TCSANOW, &new_term);
char func[100] = "x - x * x + 1349"; // char *gnuplotCommand = "gnuplot -persist -e \"plot sin(x)\" pause -1";
// system(gnuplotCommand);
// Подключение GNU Plot // Подключение GNU Plot
FILE *gp = popen("gnuplot -persist", "w"); // FILE *gp = system("gnuplot -persist");
// if (gp == NULL)
// {
// printf("GNUerror\n");
// exit(3);
// }
// fprintf(gp, "set xrange [-500:500]\n");
// fprintf(gp, "set yrange [0:500]\n");
// fprintf(gp, "plot %s, 0\n", func);
// fflush(gp); // очищение буфера вывода
printf("set terminal wxt enhanced\n");
printf("plot sin(x)\n");
printf("pause mouse keypress\n");
// system("echo 'set term x11' | gnuplot -persist");
// system("set xrange [-500:500]\n set yrange [0:500]\n echo 'plot x - x * x + 1349'\n gnuplot -persist");
// system("exit\n");
// system("set yrange [0:500]\n | gnuplot -persist");
// system("echo 'plot x - x * x + 1349' | gnuplot -persist");
if (gp == NULL)
{
printf("GNUerror\n");
exit(3);
}
fprintf(gp, "set xrange [-500:500]\n");
fprintf(gp, "set yrange [0:500]\n");
fprintf(gp, "plot %s, 0\n", func);
fflush(gp); // очищение буфера вывода
sig_flag = 1; sig_flag = 1;
printf("Нажмите любую клавишу, чтобы продолжить...\n"); printf("Нажмите любую клавишу, чтобы продолжить...\n");
getchar(); getchar();
sig_flag = 0; sig_flag = 0;
fprintf(gp, "exit\n"); // fprintf(gp, "exit\n");
tcsetattr(STDIN_FILENO, TCSANOW, &old_term); tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
return; return;
} }
+5 -1
View File
@@ -18,6 +18,10 @@ int main()
pb = &b; pb = &b;
px = &x; px = &x;
printf("set terminal wxt enhanced\n");
printf("plot sin(x)\n");
printf("pause mouse keypress\n");
struct sigaction sig_int, sig_tstp; // Инициализация структуры, отвечающей за обработку сигнала. struct sigaction sig_int, sig_tstp; // Инициализация структуры, отвечающей за обработку сигнала.
// Замена стандартного алгоритма на необходимый для вызова меню действий. // Замена стандартного алгоритма на необходимый для вызова меню действий.
sig_int.sa_handler = ctrlc_handler; sig_int.sa_handler = ctrlc_handler;
@@ -38,7 +42,7 @@ int main()
return 1; return 1;
} }
show_grapgh(); // show_grapgh();
input_diap(); input_diap();
if (*mth == 0) if (*mth == 0)
Binary file not shown.
+25
View File
@@ -0,0 +1,25 @@
# Это комментарий, который говорит, что переменная CC указывает компилятор, используемый для сборки
CC= gcc
#Это еще один комментарий. Он поясняет, что в переменной CFLAGS лежат флаги, которые передаются компилятору
CFLAGS= -c -Wall
default: build
general: main.o functions.o
$(CC) ./out/main.o ./out/functions.o -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
+35
View File
@@ -0,0 +1,35 @@
# Function Zeros Calculator
## Описание
Эта программа предназначена для вычисления нулей функции на языке C в среде Linux.
## Установка
1. Склонируйте репозиторий: git clone https://github.com/ada-dmitry/tmp_project.git
2. Перейдите в каталог проекта: cd /Project_1.2
## Использование
0. Для нормальной работы программы необходимо установить программу GNU PLot
(sudo apt install gnuplot)
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]
+23
View File
@@ -0,0 +1,23 @@
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();
+303
View File
@@ -0,0 +1,303 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <termios.h>
#include <stdio_ext.h>
#include "declare.h"
double f(double x) // Функция, заданная пользователем, для которой происходит поиск корней.
{
return x + 20;
}
void show_grapgh()
{
char func[100] = "x+20";
tcsetattr(0, TCSANOW, &modif_term);
// Подключение 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");
tcsetattr(0, TCSANOW, &default_term);
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();
// scanf("%c", &choice); // Запись буквы, введенной пользователем в переменную choice.
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)
{
printf("Аварийное завершение программы, возврат к настройкам по умолчанию...");
__exit();
}
void __exit()
{
tcsetattr(0, TCSANOW, &default_term); // Применение новых настроек терминала
exit(1);
}
void input_diap()
{
double tmp;
char input[50];
sig_flag = 1;
system("clear");
printf("\n\nТекущие значения: [%lf : %lf] eps = %lf\n\n\
Введите левую границу отрезка и нажмите Enter (по умолчанию: %lf): ",
*pa, *pb, eps, *pa);
fgets(input, sizeof(input), stdin);
if (input[0] == '\n')
{
*pa = A; // значение по умолчанию
}
else
{
sscanf(input, "%lf", pa);
}
system("clear");
printf("\n\nТекущие значения: [%lf : %lf] eps = %lf\n\n\
Введите правую границу отрезка и нажмите Enter (по умолчанию: %lf): ",
*pa, *pb, eps, *pb);
fgets(input, sizeof(input), stdin);
if (input[0] == '\n')
{
*pb = B; // значение по умолчанию
}
else
{
sscanf(input, "%lf", pb);
}
system("clear");
printf("\n\nТекущие значения: [%lf : %lf] eps = %lf\n\n\
Введите точность вычисления и нажмите Enter (по умолчанию: %lf): ",
*pa, *pb, eps, eps);
fgets(input, sizeof(input), stdin);
if (input[0] == '\n')
{
eps = EPS; // значение по умолчанию
}
else
{
sscanf(input, "%lf", &eps);
}
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");
// choose_path();
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);
printf("Введите новые значения границ a и b: ");
scanf("%lf%lf", pa, pb);
if (f(*pa) * f(*pb) > 0)
{
printf("\nВ указанных границах нуля функции не существует.\n");
printf("Поменяйте границы\n");
choose_path();
// change_diap();
}
if (*pa == *pb)
{
if (f(*pa) == 0)
{
printf("\nКорень уравнения: %lf\n", *pa);
printf("Работа программы завершена.\n");
__exit();
}
else
{
printf("Нажмите Ctrl+C и поменяйте границы\n");
}
}
sig_flag = 0;
return;
}
+81
View File
@@ -0,0 +1,81 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <stdio_ext.h>
#include <termios.h>
#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("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
BIN
View File
Binary file not shown.
Binary file not shown.