Готовые отчеты / ЛиФП. Лабораторная работа 3
.pdfФедеральное агентство связи ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ
ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ «САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М. А. БОНЧ-БРУЕВИЧА» (СПбГУТ)
Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники
ЛАБОРАТОРНАЯ РАБОТА №3 по дисциплине «Логическое и функциональное программирование»
Выполнил: студент 3-го курса дневного отделения группы ИКПИ-85
Коваленко Леонид Александрович Преподаватель:
доцент кафедры ПИиВТ Ерофеев Сергей Анатольевич
Санкт-Петербург
2020
Постановка задачи
Написать программу на языке Turbo Prolog 2.0 для нахождения корня уравнения a0 x0+a1 x1+...+an xn=0 методом половинного деления между левой границей A и правой границей B (отрезок [ A , B ] ).
Схема решения Алгоритм основан на следующем следствии из теоремы Больцано —
Коши:
• Пусть непрерывная функция f (x ) C ([ A , B]) , тогда, если f ( A) f (B)<0 ,
то C [ A , B]: f (C)=0 .
Таким образом, если мы ищем ноль, то на концах отрезка функция должна быть противоположных знаков. Разделим отрезок пополам и возьмём ту из половинок, на концах которой функция по-прежнему принимает значения противоположных знаков. Если значение функции в серединной точке оказалось искомым нулём (или близко к нулю), то процесс завершается.
Алгоритм решения кратко представлен на рис. 1.
Рисунок 1 — Алгоритм решения задачи
2
Код программы Входные данные поступают с клавиатуры либо файла, пример
содержимого которого приведен в табл. 1.
Таблица 1 — Входные данные в файле (слева) и комментарий (справа)
0 |
-- A (левая граница) |
4-- B (правая граница)
1e-6 |
-- Epsilon (точность результата) |
||||
10 |
-- Число отрезков между A и B для поиска корней |
||||
-1.0 |
-- a0 |
(x0 |
* a0) |
||
1.0 |
-- |
a1 |
(x1 |
* |
a1) |
-1.0 |
-- |
a2 |
(x2 |
* |
a2) |
1.0-- a3 (x3 * a3)
... |
... |
Код программы приведен в табл. 2. Таблица 2 — Код программы
NOWARNINGS
% Раздел описания доменов
DOMAINS
file = datafile % Файл datafile
list_of_real = real* % Список вещественных чисел
%Раздел описания предикатов
PREDICATES
length(list_of_real, integer) input(list_of_real, real, real, real, integer)
input_action(list_of_real, real, real, real, integer, integer) read_reals_from_console(list_of_real) read_reals_from_console(list_of_real, integer) read_reals_from_file(list_of_real)
find_roots(list_of_real, real, real, real, integer, list_of_real) find_root(list_of_real, real, real, real, real, real) calc_polynom(real, list_of_real, real)
calc_polynom(real, list_of_real, real, real, integer) bisection_method(list_of_real, real, real, real, real) bisection_auxillary(list_of_real, real, real, real, real, real, real, real, real) output(list_of_real, list_of_real)
output_action(list_of_real, list_of_real, integer) write_roots(list_of_real, list_of_real)
%Раздел описания внутренней цели
GOAL
input(Reals, A, B, Epsilon, S), % Ввод исходных данных
find_roots(Reals, A, B, Epsilon, S, Roots), % Поиск всех корней на отрезке [A, B] output(Reals, Roots), % Вывод результата
readchar(_). % Завершение программы после нажатия клавиши клавиатуры
%Раздел констант
CONSTANTS
dx = 1e-3 % Разность между реальными и мнимыми границами (для отрезка [a, b])
%Раздел описания предложений
CLAUSES
%Длина списка length([], 0). length([_|Xs], N) :-
length(Xs, P),
N = P + 1.
%Ввод исходных данных
input(Reals, A, B, Epsilon, S) :- write("-== MENU ==-"), nl, write("1. Read from console;"), nl, write("2. Read from file."), nl, write("Another button to exit"), nl,
readint(C), % Считывание целого числа input_action(Reals, A, B, Epsilon, S, C), % Ввод
3
length(Reals, Length), Length >= 2;
write("Invalid input or no roots!"), fail. % Если неверный ввод
% Ввод из диалогового окна
input_action(Reals, A, |
B, Epsilon, S, 1) |
:- |
write("Enter A:"), |
readreal(At), |
|
write("Enter B:"), |
readreal(Bt), |
|
A = At - dx, % Для |
работы с отрезком |
[a, b], |
B = Bt + dx, % А не с интервалом (a, b) A < B, % Согласно f(A) * f(B) < 0 write("Epsilon: "), readreal(Epsilon), Epsilon < 1, % Разумный поиск корней write("Segments: "), readint(S),
S >= 1, % Разумное число сегментов read_reals_from_console(Reals).
% Ввод из файла
input_action(Reals, A, B, Epsilon, S, 2) :- write("File name: "), readln(FileName), % Ввод названия файла
existfile(FileName), % Существует ли файл openread(datafile, FileName), % Открытие файла для чтения readdevice(datafile), % Перенаправление ввода на файл readreal(At), readreal(Bt), % Чтение границ
A = At - dx, % Для работы с отрезком [a, b], B = Bt + dx, % А не с интервалом (a, b)
A < B, % Правильные границы
readreal(Epsilon), Epsilon < 1, % Разумный поиск корней readint(S), S >= 1, % Разумное число сегментов read_reals_from_file(Reals), % Чтение коэффициентов closefile(datafile), !; % Закрытие файла
write("Error reading file!"), nl, fail.
% Чтение с консоли
read_reals_from_console(X) :- read_reals_from_console(X, 0). read_reals_from_console([Head|Tail], N) :-
write("x^", N, " * "), readreal(Head), % Чтение коэффициента N1 = N + 1,
read_reals_from_console(Tail, N1). read_reals_from_console([], _).
% Чтение с файла read_reals_from_file([Head|Tail]) :-
readreal(Head), % Чтение коэффициента read_reals_from_file(Tail).
read_reals_from_file([]). |
|
|||
% Пример содержимого |
файла: |
|||
% -4.0 |
% |
A |
|
|
% |
4.0 |
% |
B |
|
% |
1e-6 |
% |
Epsilon |
|
% |
1 |
% |
S |
(segments) |
% -1.0 |
% |
* |
X^0 |
|
% |
1.0 |
% |
* |
X^1 |
% -1.0 |
% |
* |
X^2 |
|
% |
1.0 |
% |
* |
X^3 |
% Поиск всех корней на |
отрезке [A, B] |
find_roots(Reals, A, B, Epsilon, S, Roots) :-
D = (abs(A) + abs(B)) / (S + 1),
findall(Root, find_root(Reals, A, B, Epsilon, D, Root), Roots).
find_root(_, A, B, _, _, _) :- A >= B, !, fail. find_root(Reals, A, B, Epsilon, D, Root) :-
AD = A + D,
bisection_method(Reals, A, AD, Epsilon, Root); AD = A + D,
find_root(Reals, AD, B, Epsilon, D, Root).
% Метод половинного деления bisection_method(Reals, A, B, Epsilon, Root) :-
calc_polynom(A, Reals, FA), % Вычисляем значение при x=A calc_polynom(B, Reals, FB), % Вычисляем значение при x=B FA * FB < 0, % Знаки на границах должны быть разными
X = (A + B) / 2, % Вычисляем среднюю точку
calc_polynom(X, Reals, FX), % Вычисляем значение при x=Mean bisection_auxillary(Reals, A, B, FA, FB, X, FX, Epsilon, Root).
% Вспомогательный предикат для метода половинного деления bisection_auxillary(_, _, _, _, _, X, FX, Epsilon, Root) :-
abs(FX) < Epsilon, Root = X, !; % Если очень близок к 0, то корень найден abs(FX) = 0, Root = X, !. % Также корень найден, если f(x) = 0
bisection_auxillary(Reals, A, B, FA, FB, X, FX, Epsilon, Root) :-
4
FA * FX < 0, % Если знаки на границах A - Mean разные bisection_method(Reals, A, X, Epsilon, Root), !; % Ищем в левой части FB * FX < 0, % Если знаки на границах Mean - B разные bisection_method(Reals, B, X, Epsilon, Root). % Ищем в правой части
%Функция вычисления значения полинома calc_polynom(X, List, R) :-
calc_polynom(X, List, R, 1, 0), !. calc_polynom(_, [], 0, _, _). calc_polynom(X, [Head|Tail], R, _, 0) :-
calc_polynom(X, Tail, R1, X, 1), R = R1 + Head, !. calc_polynom(X, [Head|Tail], R, P, N) :-
PX = P * X,
calc_polynom(X, Tail, R1, PX, N),
R = R1 + P * Head.
%Вывод результата
output(Reals, []) :- write("No roots!"), nl, !. output(Reals, Roots) :-
write("1. Write to console;"), nl, write("2. Write to file."), nl, write("Another button to exit"), nl, readint(C), % Считывание числа output_action(Reals, Roots, C); % Вывод write("The program is complete.").
% Вывод в диалоговое окно output_action(Reals, Roots, 1) :-
write_roots(Reals, Roots).
% Вывод в файл output_action(Reals, Roots, 2) :-
write("File name: "), readln(FileName), % Ввод названия файла
openwrite(datafile, FileName), % Открытие файла для записи writedevice(datafile), % Перенаправление вывода на файл write_roots(Reals, Roots), % Запись данных closefile(datafile). % Закрытие файла
% Вывод найденного корня write_roots(Reals, []). write_roots(Reals, [X|Tail]) :-
calc_polynom(X, Reals, FX),
writef("X=%0.8f", X), nl, writef("F(X)=%0.8f", FX), nl, nl, write_roots(Reals, Tail).
Тестирование
Программа тестировалась на следующих функциях и отрезках (табл. 3). Таблица 3 — Функции и отрезки, на которых тестировалась программа
Функция |
Отрезок |
Число |
Результат программы |
||
отрезков |
|||||
|
|
|
|
||
f (x )=−1+x−x2 + x3 |
[0 , 4 ] |
10 |
x=1, f (x)=0 |
||
f (x )=−1+x−x2 + x3 |
[1 , 4] |
|
10 |
x=1, f (x)=0 |
|
f (x )=−1+x−x2 + x3 |
[0 , 1] |
|
10 |
x=1, f (x)=0 |
|
f (x )=−1+x−x2 + x3 |
[0 , 0.9 |
] |
10 |
No roots! |
|
f (x )=−1+x−x2 + x3 |
[1.1 , 4 |
] |
10 |
No roots! |
|
|
|
|
|
x=0 , f (x)=0 |
|
f (x )=0−x +5 x2−4 x3−3 x4 +2 x5 +x6 |
[−1 , 2] |
10 |
x=0.26523093 ,f (x)=0 |
||
x=0.85706167 ,f (x )=0 |
|||||
|
|
|
|
||
|
|
|
|
x=1, f (x)=0 |
Во всех случаях результаты программы округленно совпадали с результатами, найденными вручную.
5
Входные данные для последнего примера приведены в табл. 4, а результат работы программы в табл. 5.
Таблица 4 — Файл с входными данными
-1 2 1e-9 10 0 -1 5 -4 -3 2 1
Таблица 5 — Файл с результатом
X=0.00000000
F(X)=-0.00000000
X=0.26523093
F(X)=-0.00000000
X=0.85706167
F(X)=-0.00000000
X=1.00000000 F(X)=-0.00000000
Выводы В результате выполнения лабораторной работы мы разработали
программу на языке Turbo Prolog 2.0 для нахождения корня уравнения методом половинного деления между левой границей A и правой границей B (отрезок ). Было проведено тестирование
отдельных предикатов и всей программы в целом. Программа полностью удовлетворяет заданным требованиям.
6