Чтение онлайн

на главную - закладки

Жанры

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

Vector back_substitution(const Matrix& A, const Vector& b)

{

const Index n = A.dim1;

Vector x(n);

for (Index i = n – 1; i >= 0; ––i) {

double s = b(i)–dot_product(A[i].slice(i+1),x.slice(i+1));

if (double m = A(i, i))

x(i) = s / m;

else

throw Back_subst_failure(i);

}

return x;

}

24.6.2.

Выбор ведущего элемента

Для того чтобы избежать проблем с нулевыми диагональными элементами и повысить устойчивость алгоритма, можно переставить строки так, чтобы нули и малые величины на диагонали не стояли. Говоря “повысить устойчивость”, мы имеем в виду понижение чувствительности к ошибкам округления. Однако по мере выполнения алгоритма элементы матрицы будут изменяться, поэтому перестановку строк приходится делать постоянно (иначе говоря, мы не можем лишь один раз переупорядочить матрицу, а затем применить классический алгоритм).

void elim_with_partial_pivot(Matrix& A, Vector& b)

{

const Index n = A.dim1;

for (Index j = 0; j < n; ++j) {

Index pivot_row = j;

// ищем подходящий опорный элемент:

for (Index k = j + 1; k < n; ++k)

if (abs(A(k, j)) > abs(A(pivot_row, j))) pivot_row = k;

// переставляем строки, если найдется лучший опорный

// элемент

if (pivot_row != j) {

A.swap_rows(j, pivot_row);

std::swap(b(j), b(pivot_row));

}

// исключение:

for (Index i = j + 1; i < n; ++i) {

const double pivot = A(j, j);

if (pivot==0) error("Решения нет: pivot==0");

onst double mult = A(i, j)/pivot;

A[i].slice(j) = scale_and_add(A[j].slice(j),

–mult, A[i].slice(j));

b(i) –= mult * b(j);

}

}

}

Для того чтобы не писать циклы явно и привести код в более традиционный вид, мы используем функции

swap_rows
и
scale_and_multiply
.

24.6.3. Тестирование

Очевидно, что мы должны протестировать нашу программу. К счастью, это сделать несложно.

void solve_random_system(Index n)

{

Matrix A = random_matrix(n); // см. раздел 24.7

Vector b = random_vector(n);

cout << "A = " << A << endl;

cout << "b = " << b << endl;

try {

Vector x = classical_gaussian_elimination(A, b);

cout << "Решение
методом Гаусса x = " << x << endl;

Vector v = A * x;

cout << " A * x = " << v << endl;

}

catch(const exception& e) {

cerr << e.what << std::endl;

}

}

Существуют три причины, из-за которых можно попасть в раздел

catch
.

• Ошибка в программе (однако, будучи оптимистами, будем считать, что этого никогда не произойдет).

• Входные данные, приводящие к краху алгоритма

classical_elimination
(целесообразно использовать функцию
elim_with_partial_pivot
).

• Ошибки округления.

Тем не менее наш тест не настолько реалистичен, как мы думали, поскольку случайные матрицы вряд ли вызовут проблемы с алгоритмом

classical_elimination
.

Для того чтобы проверить наше решение, выводим на экране произведение

A*x
, которое должно быть равно вектору
b
(или достаточно близким к нему с учетом ошибок округления). Из-за вероятных ошибок округления мы не можем просто ограничиться инструкцией

if (A*x!=b) error("Неправильное решение");

Поскольку числа с десятичной точкой являются лишь приближением действительных чисел, получим лишь приближенный ответ. В принципе лучше не применять операторы

==
и
!=
к результатам вычислений с десятичными точками: такие числа являются лишь приближениями.

В библиотеке

Matrix
нет операции умножения матрицы на вектор, поэтому эту функцию нам придется написать самостоятельно.

Vector operator*(const Matrix& m,const Vector& u)

{

const Index n = m.dim1;

Vector v(n);

for (Index i = 0; i < n; ++i) v(i) = dot_product(m[i], u);

return v;

}

И вновь простая операция над объектом класса

Matrix
делает за нас большую часть работы. Как указывалось в разделе 24.5.3, операции вывода объектов класса
Matrix
описаны в заголовке
MatrixIO.h
. Функции
random_matrix
и
random_vector
просто используют случайные числа (раздел 24.7). Читатели могут написать эти функции в качестве упражнения. Имя
Index
является синонимом типа индекса, используемого в библиотеке
Matrix
, и определено с помощью оператора
typedef
(раздел A.15). Этот тип включается в программу с помощью объявления
using
.

Поделиться:
Популярные книги

Вираж бытия

Ланцов Михаил Алексеевич
1. Фрунзе
Фантастика:
героическая фантастика
попаданцы
альтернативная история
6.86
рейтинг книги
Вираж бытия

Кодекс Крови. Книга IХ

Борзых М.
9. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга IХ

Эфемер

Прокофьев Роман Юрьевич
7. Стеллар
Фантастика:
боевая фантастика
рпг
7.23
рейтинг книги
Эфемер

Попаданка в академии драконов 4

Свадьбина Любовь
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Попаданка в академии драконов 4

Крестоносец

Ланцов Михаил Алексеевич
7. Помещик
Фантастика:
героическая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Крестоносец

Промышленникъ

Кулаков Алексей Иванович
3. Александр Агренев
Приключения:
исторические приключения
9.13
рейтинг книги
Промышленникъ

Ротмистр Гордеев 2

Дашко Дмитрий
2. Ротмистр Гордеев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Ротмистр Гордеев 2

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Фиктивный брак

Завгородняя Анна Александровна
Фантастика:
фэнтези
6.71
рейтинг книги
Фиктивный брак

Набирая силу

Каменистый Артем
2. Альфа-ноль
Фантастика:
фэнтези
боевая фантастика
рпг
6.29
рейтинг книги
Набирая силу

Имперец. Земли Итреи

Игнатов Михаил Павлович
11. Путь
Фантастика:
героическая фантастика
боевая фантастика
5.25
рейтинг книги
Имперец. Земли Итреи

Титан империи

Артемов Александр Александрович
1. Титан Империи
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Титан империи

Странник

Седой Василий
4. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Странник

Мне нужна жена

Юнина Наталья
Любовные романы:
современные любовные романы
6.88
рейтинг книги
Мне нужна жена