Учебник Turbo Pascal. Введение - Вычисление корня функции методом деления отрезка пополам

ОГЛАВЛЕНИЕ

Вычисление корня функции методом деления отрезка пополам

В следующем примере запрограммировано вычисление корня функции методом деления отрезка пополам. Напомню, что корень функции F(x) — это такое значение ее аргумента х*, при котором выполняется условие F(x*) = 0. Известно, что для решения такого уравнения надо вначале задать интервал [а, Ь], на котором будет искаться решение. Если решение действительно существует, принадлежит заданному интервалу и является на этом интервале единственным, функция F(x) принимает на границах интервала значения противоположных знаков. Другими словами, произведение значений функции на границах интервала отрицательно: F(a)F(b) < 0. Далее исходный интервал делится средней точкой с = (а+b)/2 на две равные части, из которых выбирается лишь та, которая содержит решение уравнения. Процедура деления отрезка пополам повторяется до тех пор, пока корень функции не будет найден с заданной точностью. Оценкой погрешности в данном случае может быть величина последнего интервала |а-b| или значение |F(x)|. Последний критерий используется в программе, приведенной в листинге 1.11.

Листинг 1.11. Решение нелинейного уравнения методом деления отрезка пополам

{$N+}
program bisection;
type
    real_function = function (x: Real): Real;

function G(x: Real): Real; far;
begin
    G := Sqr(x) - 2.0;
end;

function zero(F: real_function; x, y: Real): Real;
const
    eps = 1.0e-12;
var
    mid, fx, fy, fm: Real;
begin
    fx := F(x);
    fy := F(y);
    if fx * fy > 0.0 then
        Halt; {Прекращение работы подпрограммы, если на выбранном участке нет корня}
    repeat
        if Abs(fx) < eps then
        begin
            zero := x;
            Exit;
        end
        else if Abs(fy) < eps then
        begin
            zero := y;
            Exit;
        end
        else begin
            mid := 0.5 * (x + y);
            fm := F(mid);
            if fx*fm <= 0 then
            begin
                у := mid;
                fy := fm;
            end
            else begin
                x := mid;
                fx := fm;
            end;
        end
    until false;
end;
    
begin
    WriteLn('G(', zero(G, 1.0, 2.0):10:10, ') = 0');
    ReadLn;
end.

Остановимся подробнее на этой программе. Вторая строка содержит оператор type, разговор о котором пойдет позже. Сейчас же скажу, что этот оператор позволяет программисту ввести свой собственный тип. Слева от знака равенства записывается название нового типа данных, а справа задается сам этот тип. В нашем случае это функциональный тип. В третьей строке программы используется новый для нас элемент — ключевое слово far. Это директива компилятора, которая используется в описаниях подпрограмм, передаваемых в качестве параметров другим подпрограммам. Такой подпрограммой в нашем случае является подпрограмма-функция G. Она используется в качестве аргумента другой подпрограммы-функции zero. В функции zero запрограммировано вычисление корня произвольной непрерывной функции, имеющей на границах исходного интервала противоположные знаки. Использование функции G в качестве аргумента подпрограммы-функции zero делает программу более универсальной, ведь для решения другого нелинейного уравнения достаточно будет подставить в данную программу описание другой функции.

Оператор цикла repeat...until... в программе сделан бесконечным, так как условие завершения — просто логическая константа false. Если окажется, что корень функции найден с заданной точностью, будет выполняться условный оператор, следующий сразу же за заголовком цикла, а его выполнение завершится вызовом процедуры Exit. Эта процедура завершает выполнение функции. Если условие противоположности знаков нарушено, процедура Halt остановит выполнение программы. В этом случае у функции на заданном интервале нет корня.