- •Логические данные
- •Символьные данные
- •Хранение текста
- •Арифметические данные
- •Данные с фиксированной точкой
- •1111111101000111(2) - Инвертируем биты - 0000000010111000(2)
- •Данные с плавающей точкой
- •Простейшие приемы анализа погрешностей.
- •Методы оптимизации
- •Данные системы Turbo Pascal
- •Способы вычисления логических операций
- •Подпрограммы и их параметры
- •Способы передачи параметров
- •Структурное программирование, управляющие конструкции, пошаговая детализация.
- •Рекурсия и итерация
- •Метод итераций (повторений)
- •Метод инварианта цикла.
- •Метод инвариантной функции.
- •Метод индуктивной функции.
- •Защитное программирование
- •Абстрактные типы данных
- •Использование объектных средств
- •Динамические структуры данных
- •Языки и грамматики
- •Расширение нотации Бэкуса-Наура.
- •Интерпретатор математических формул, реализованный на основе метода Дейкстры.
- •Абстрактные структуры данных.
- •Часть 2 Последовательность.
- •Динамический вектор.
- •Множество
- •Нагруженное множество
- •Итераторы.
Метод итераций (повторений)
Пусть М – некоторое множество (значения должны быть допустимы ), Р подмножество М, где Р – множество решений. При этом х Р p(х)=истина. Пусть Т некоторое преобразование из М\Р в М, т.е. Т:М\РМ.
Метод итераций (дословно – повторений) состоит в том, что строится некоторое преобразование (отображение) Т:М\РМ и это преобразование последовательно применяется, начиная с какого-то х0M:
X1=T(x0), x2=T(x1), …, xn=T(xn-1), …
до тех пор, пока мы впервые не получим xi такое, что p(xi)=истина (естественно, должна быть уверенность, что рано или поздно такое xi найдется).
Напишем программу, находящую х. Пусть х0М (некоторая точка М) – начальное значение.
x :=х0; {хМ}
while not p(x) do
begin
{xM\P}
x :=T(x);
{xM}
end;
{xP}
Для корректности данной программы необходимо и достаточно доказать, что цикл завершится за конечное число шагов.
Иллюстрация работы программы:
При этом множества М и Р могут быть выбраны различными способами.
Примеры:
1. Вычисление интеграла Римана
Для вычисления интеграла необходимо разбить отрезок [a,b] на р частей. При этом Ip I, где Ip – квадратурная форма. Если увеличить количество разбиений в к раз, то получим Ipk I. При этом если подынтегральная функция достаточно гладкая, то I - Ikp = ( Ikp - Ip )/(ks+1-1)+o(p-s), где s – степень точности формулы. Данная формула оценки погрешности через старший член лежит в основе метода Рунге.
При этом величина Ikp + (Ikp - Ip)/(ks+1 - 1) будет точнее, чем Ikp. Она носит название первого шага метода Ромберга.
Рассмотрим программу вычисления интеграла.
{$N+}
Type _Real = single;
fr2r = function (x: _Real):_Real;
Function Integral (a, b: _Real; f: fr2r; eps: Real):Real;
{a, b – пределы интегрирования, f – достаточно гладкая подынтегральная функция; eps>0 – критерий Рунге. Функция возвращает приближенное значение интеграла Римана}
var
Iprev, Ipost, R: _Real;
p: word;
h: _Real;
const p0=16;
k=2;{или 3}
gamma=…..{ks+1-1};
{далее могут следовать другие необходимые константы}
begin
if a=b then begin Integral:=0.0; exit; end;
p:=p0;
h:=(b-a)/p;
{Вычисление Ipost для числа разбиений p, а также, возможно, его частей}
R:=1e30;
While abs (R) > eps do
Begin
Iprev := Ipost;
P := p*k;
h := h/k;{p-иногда не обязателен}
{Вычисляем Ipost для p разбиений, и, возможно, его части}
R := (Ipost- Iprev)/gamma;
End;
Integral := Ipost+R;
End;
Замечания:
Процесс сопровождают погрешности округления. Поэтому если eps выбрать достаточно малой, то процесс зациклится.
Вычисление квадратурных сумм следует организовать так, чтобы погрешность была меньше. Для этого, например, суммы необходимо накапливать с более высокой точностью.
2. Вычисление функции Бесселя J0(x) = (-1)k((x/2)2k/(k!)2), где k изменяется от 0 до . С другой стороныJ0(x)(-1)k((x/2)2k/(k!)2).
Данный ряд сходится к функции Бесселя при любом значении аргумента.
Суммирование производится до тех пор, пока элемент ряда не станет меньше значения погрешности, т.е. aN <eps.
Напишем простейшую программу подсчитывающую значение функции Бесселя по ряду.
Function J0 (x, eps : _Real):_Real;
{x – аргумент функции, eps>0 – погрешность округления. Функция возвращает приближенное значение функции Бесселя}
var
k : word;
a, s : _Real;
begin
k := 0;
a :=1.0;
s := 1.0;
while abs(a) > eps do
begin
k := k + 1;
a := -a * sqr (x/2.0) / sqr (k);
s:=s+a;
end;
j0 := s;
end;
При этом k лучше было бы хранить как вещественное число.
Для увеличения скорости работы программы удобно затабулировать квадрат знаменателя. Запишем разность знаменателей на следующих один за другим шагах цикла. Zk+1 = (k+1)2-k2 = 2k + 1, в свою очередь, табулируя полученную линейную функцию, получаем Uk+1 = Zk+1 –Zk = 2. Таким образом нахождение k2 сводится к сложению представленному следующей таблицей:
Теперь мы можем написать подпрограмму, которая будет несравненно лучше предыдущей.
Type _Real = single;
Function J0 (x, eps : _Real) : _Real;
{x – значение аргумента, eps>0 – погрешность округления. Функция возвращает приближенное значение функции Бесселя}
const u : _Real = 2.0;
var
s, a, z, z0, r : _Real;
begin
a := 1.0;
s := a;
z := -1.0;
z0 := 0.0;
r := -sqr (x/2.0);
while abs (a) > eps do
begin
z := z + u;
z0 := z0 + z;
a := a*r/z0;
s:=s+a;
end;
J0 := s;
end;
Математические свойства данной программы будут те же, т.к. используется тот же математический аппарат.
Функция Бесселя, вычисляемая в данной программе характеризуется следующими графиками :
maxak ((x/2)2[x/2]/([x/2]!)2)
maxak 1-t maxak, где t – длина мантиссы, - основание системы счисления принятой в компьютере.
Таким образом, не следует брать слишком маленькие значения eps. Минимальное значение eps зависит от х и возрастает с ростом модуля х.
Из всего вышесказанного можно сделать вывод, что метод рядов Тейлора хотя и является хорошим математическим аппаратом для исследований, но не приспособлен для вычислений, т.к. область его применения ограничивается небольшой окрестностью точки разложения (в данном случае точки 0).