Скачиваний:
0
Добавлен:
22.09.2026
Размер:
3 Мб
Скачать
☆
Блок-схема подпрограммы write_coefficients_to_file(*filename,
*coefficients, order)
Блок-схема подпрограммы gauss_elimination(**A, *b, n, *x)
Блок-схема подпрограммы least_squares_laguerre(*points, num_points,
order, *coefficients)
Блок-схема подпрограммы create_plot_data(*points, num_points,
*coefficients,order, *filename)
4. Код программы
/* Подключаем необходимые стандартные библиотеки */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
/* Определяем структуру для хранения точек с координатами x и y */
typedef struct {
double x; // Координата x точки
double y; // Координата y точки
} Point;
/*
* Функция вычисления значения полинома Лаггера порядка k в точке x
*/
double laguerre(int k, double x) {
// Базовые случаи рекурсии
if (k == 0) return 1.0; // L₀(x) = 1
if (k == 1) return 1.0 - x; // L₁(x) = 1 - x
// Инициализация значений для полиномов порядков 0 и 1
double L0 = 1.0; // L₀(x)
double L1 = 1.0 - x; // L₁(x)
double Lk = 0.0; // Здесь будет храниться результат
// Вычисление полинома по рекуррентной формуле
for (int n = 2; n <= k; n++) {
// Рекуррентная формула для полиномов Лаггера:
Lk = ((2 * n - 1 - x) * L1 - (n - 1) * L0) / n;
// Сдвигаем значения для следующей итерации
L0 = L1;
L1 = Lk;
}
return L1; // Возвращаем вычисленное значение
}
/*
* Функция бинарного поиска позиции для вставки элемента
*/
int binary_search(Point *points, Point item, int low, int high) {
// Если правая граница меньше или равна левой
if (high <= low)
// Возвращаем low+1 если item больше points[low], иначе low
return (item.x > points[low].x) ? (low + 1) : low;
// Вычисляем середину диапазона
int mid = (low + high) / 2;
// Если элемент равен среднему
if (item.x == points[mid].x)
return mid + 1; // Вставляем после среднего
// Если элемент больше среднего, ищем в правой половине
if (item.x > points[mid].x)
return binary_search(points, item, mid + 1, high);
// Иначе ищем в левой половине
return binary_search(points, item, low, mid - 1);
}
/*
* Функция сортировки вставками с бинарным поиском
*/
void binary_insertion_sort(Point *points, int n) {
// Начинаем со второго элемента (i = 1)
for (int i = 1; i < n; i++) {
Point item = points[i]; // Текущий элемент для вставки
int j = i - 1; // Индекс предыдущего элемента
// Находим позицию для вставки через бинарный поиск
int loc = binary_search(points, item, 0, j);
// Сдвигаем элементы, чтобы освободить место для вставки
while (j >= loc) {
points[j + 1] = points[j];
j--;
}
// Вставляем элемент на найденную позицию
points[j + 1] = item;
}
}
/*
* Функция решения системы линейных уравнений методом Гаусса
*/
void gauss_elimination(double **A, double *b, int n, double *x) {
// Прямой ход метода Гаусса
for (int k = 0; k < n; k++) {
// Поиск строки с максимальным элементом в текущем столбце
int max_row = k;
for (int i = k + 1; i < n; i++) {
if (fabs(A[i][k]) > fabs(A[max_row][k])) {
max_row = i;
}
}
// Если нашли строку с большим элементом, меняем строки местами
if (max_row != k) {
// Меняем строки в матрице A
double *temp_row = A[k];
A[k] = A[max_row];
A[max_row] = temp_row;
// Меняем соответствующие элементы в векторе b
double temp_b = b[k];
b[k] = b[max_row];
b[max_row] = temp_b;
}
// Исключение переменной из нижележащих строк
for (int i = k + 1; i < n; i++) {
double factor = A[i][k] / A[k][k]; // Вычисляем
множитель
// Вычитаем из текущей строки ведущую строку, умноженную на множитель
for (int j = k; j < n; j++) {
A[i][j] -= factor * A[k][j];
}
// Аналогично для вектора b
b[i] -= factor * b[k];
}
}
// Обратный ход метода Гаусса
for (int i = n - 1; i >= 0; i--) {
x[i] = b[i]; // Начинаем с соответствующего элемента вектора b
// Вычитаем известные переменные
for (int j = i + 1; j < n; j++) {
x[i] -= A[i][j] * x[j];
}
// Делим на диагональный элемент
x[i] /= A[i][i];
}
}
/*
* Функция аппроксимации методом наименьших квадратов с полиномами Лаггера
*/
void least_squares_laguerre(Point *points, int num_points, int
order, double *coefficients) {
// Выделяем память для матрицы системы уравнений
double **A = (double **)malloc((order + 1) * sizeof(double *));
for (int i = 0; i <= order; i++) {
A[i] = (double *)malloc((order + 1) * sizeof(double));
}
// Выделяем память для правой части системы
double *b = (double *)malloc((order + 1) * sizeof(double));
// Заполняем матрицу A и вектор b
for (int i = 0; i <= order; i++) {
for (int j = 0; j <= order; j++) {
A[i][j] = 0.0; // Инициализируем элемент
// Вычисляем скалярное произведение L_i и L_j
for (int k = 0; k < num_points; k++) {
A[i][j] += laguerre(i, points[k].x) * laguerre(j,
points[k].x);
}
}
b[i] = 0.0; // Инициализируем элемент вектора b
// Вычисляем скалярное произведение y и L_i
for (int k = 0; k < num_points; k++) {
b[i] += points[k].y * laguerre(i, points[k].x);
}
}
// Решаем систему уравнений A*coefficients = b
gauss_elimination(A, b, order + 1, coefficients);
// Освобождаем выделенную память
for (int i = 0; i <= order; i++) {
free(A[i]);
}
free(A);
free(b);
}
/*
* Функция записи коэффициентов в файл
*/
void write_coefficients_to_file(const char *filename, double
*coefficients, int order) {
// Открываем файл для записи
FILE *file = fopen(filename, "w");
if (file == NULL) {
printf("Ошибка при открытии файла для записи коэффициентов.\n");
return;
}
// Записываем заголовок
fprintf(file, "Коэффициенты полинома Лаггера (порядок %d):\n", order);
// Записываем коэффициенты
for (int i = 0; i <= order; i++) {
fprintf(file, "a%d = %lf\n", i, coefficients[i]);
}
// Закрываем файл
fclose(file);
}
/*
* Функция создания файла данных для построения графика
*/
void create_plot_data(Point *points, int num_points, double
*coefficients, int order, const char *filename) {
// Открываем файл для записи
FILE *file = fopen(filename, "w");
if (file == NULL) {
printf("Ошибка при создании файла данных для графика.\n");
return;
}
// Записываем исходные точки
fprintf(file, "# Исходные данные\n");
for (int i = 0; i < num_points; i++) {
fprintf(file, "%lf %lf\n", points[i].x, points[i].y);
}
// Добавляем разделитель для gnuplot
fprintf(file, "\n\n# Аппроксимация\n");
// Вычисляем диапазон x
double x_start = points[0].x;
double x_end = points[num_points - 1].x;
// Генерируем 100 точек аппроксимирующей кривой
for (int i = 0; i < 100; i++) {
double x = x_start + i * (x_end - x_start) / 99;
double y = 0.0;
// Вычисляем значение полинома в точке x
for (int j = 0; j <= order; j++) {
y += coefficients[j] * laguerre(j, x);
}
fprintf(file, "%lf %lf\n", x, y);
}
// Закрываем файл
fclose(file);
}
/*
* Основная функция программы
*/
int main() {
char input_filename[256]; // Буфер для имени входного файла
char coefficients_filename[256] = "coefficients.txt"; //
Файл для коэффициентов
char plot_data_filename[256] = "plot_data.txt"; // Файл для
данных графика
// Запрашиваем имя файла с данными
printf("Введите имя файла с данными: ");
scanf("%255s", input_filename);
// Открываем файл для чтения
FILE *input_file = fopen(input_filename, "r");
if (input_file == NULL) {
printf("Ошибка при открытии файла с данными.\n");
return 1;
}
// Чтение данных из файла
Point *points = NULL; // Указатель на массив точек
int num_points = 0; // Количество точек
double x, y; // Временные переменные для чтения
// Читаем точки пока есть данные в файле
while (fscanf(input_file, "%lf %lf", &x, &y) == 2) {
num_points++;
// Увеличиваем массив точек
points = (Point *)realloc(points, num_points *
sizeof(Point));
points[num_points - 1].x = x;
points[num_points - 1].y = y;
}
fclose(input_file); // Закрываем файл
// Проверяем, есть ли данные
if (num_points == 0) {
printf("Файл не содержит данных.\n");
free(points);
return 1;
}
// Сортируем точки по возрастанию x
binary_insertion_sort(points, num_points);
// Запрашиваем порядок полинома у пользователя
int order;
printf("Введите порядок полинома Лаггера: ");
scanf("%d", &order);
// Проверяем корректность порядка
if (order < 0 || order >= num_points) {
printf("Недопустимый порядок полинома.\n");
free(points);
return 1;
}
// Выделяем память для коэффициентов
double *coefficients = (double *)malloc((order + 1) *
sizeof(double));
// Вычисляем коэффициенты аппроксимирующего полинома
least_squares_laguerre(points, num_points, order, coefficients);
// Выводим коэффициенты на экран
printf("Коэффициенты полинома Лаггера:\n");
for (int i = 0; i <= order; i++) {
printf("a%d = %lf\n", i, coefficients[i]);
}
// Записываем коэффициенты в файл
write_coefficients_to_file(coefficients_filename, coefficients, order);
printf("Коэффициенты записаны в файл '%s'.\n", coefficients_filename);
// Создаем файл данных для построения графика
create_plot_data(points, num_points, coefficients, order, plot_data_filename);
printf("Данные для построения графика записаны в файл '%s'.\n", plot_data_filename);
// Освобождаем выделенную память
free(points);
free(coefficients);
// Пытаемся построить график с помощью gnuplot
printf("Построение графика...\n");
FILE *gnuplot = popen("gnuplot -persistent", "w");
if (gnuplot != NULL) {
// Устанавливаем параметры графика
fprintf(gnuplot, "set title 'Аппроксимация полиномами Лаггера'\n");
fprintf(gnuplot, "set xlabel 'x'\n");
fprintf(gnuplot, "set ylabel 'y'\n");
// Команда построения графика
fprintf(gnuplot, "plot '%s' index 0 with points title 'Исходные данные', ", plot_data_filename);
fprintf(gnuplot, "'%s' index 1 with lines title 'Аппроксимация (порядок %d)'\n", plot_data_filename, order);
fflush(gnuplot); // Сбрасываем буфер
pclose(gnuplot); // Закрываем канал
} else {
printf("Ошибка при запуске gnuplot. Убедитесь, что gnuplot установлен и доступен в PATH.\n");
}
return 0; // Успешное завершение программы
}
5. UML-диаграммы
Диаграмма сценариев
Соседние файлы в папке Лабы