Добавил:
СПбГУТ * ИКСС * Программная инженерия Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Готовые отчеты / ЛиФП. Лабораторная работа 3

.pdf
Скачиваний:
44
Добавлен:
27.03.2021
Размер:
117.35 Кб
Скачать

Федеральное агентство связи ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ

ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ «САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М. А. БОНЧ-БРУЕВИЧА» (СПбГУТ)

Факультет инфокоммуникационных сетей и систем Кафедра программной инженерии и вычислительной техники

ЛАБОРАТОРНАЯ РАБОТА №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+xx2 + x3

[0 , 4 ]

10

x=1, f (x)=0

f (x )=−1+xx2 + x3

[1 , 4]

 

10

x=1, f (x)=0

f (x )=−1+xx2 + x3

[0 , 1]

 

10

x=1, f (x)=0

f (x )=−1+xx2 + x3

[0 , 0.9

]

10

No roots!

f (x )=−1+xx2 + 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

[ A ,B ]
a0 x0+a1 x1+...+an xn=0

Входные данные для последнего примера приведены в табл. 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