Разработка DLL на языке С++, страница 2

__declspec(dllexport) bool Solve (Geometry* p, double**& u, int ny, int nx)

{

error = "No solving module";

progress = 100;

return true;

}

BOOL APIENTRY DllMain (HANDLE hModule, DWORD reason, LPVOID lpReserved)

{

switch (reason)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH: break;

}

return TRUE;

}

В файл stdafx.h, определяющий содержимое Precompiled Header, введите изменения так, чтобы он стал:

#pragma once

#include <stdio.h>

#define WIN32_LEAN_AND_MEAN    // Exclude rarely-used stuff from Windows headers

#include <windows.h>

Обратимся к коду. Матрица имеет тип double**, то есть адрес массива адресов массивов переменных типа double. Количество звезд при определении указателя называтся глубиной или уровнем косвенности ссылок (indirection level). Так как функции AllocMatrix и ClearMatrix будут изменять адрес массива адресов, который должен вернуться в вызывающую программу, то мы передаем его по ссылке (см. тип параметра double**&). Если решается только одна система уравнений, то вектор правых частей системы целесообразно хранить вместе с матрицей коэффициентов в виде еще одного (n+1)-го столбца. Образуется так называемая расширенная матрица системы, где n строк и n+1 столбец.

Алгоритм метода исключения неизвестных состоит из двух частей: прямого хода, в котором матрица приводится к треугольному виду, и обратной подстановки, в котором вектор решения рекуррентно вычисляется, начиная с последнего элемента. Исходная матрица в ходе исключения разрушается. Для повышения численной устойчивости используют модификацию алгоритма, так называемое исключение с выбором ведущего элемента. Наш алгоритм не использует выбор ведущего элемента, поэтому он значительно проще, чем в стандартной библиотеке (например, Форсайта и Моллера).

Класс Geometry в данной версии не работает, он лишь иллюстрирует возможности экспорта. В полной версии DLL он хранит геометрию двухмерной области пространства, в которой производится расчет физического поля.

Текущим, или ведущим элементом в ходе Гаусса считается диагональный (осевой — pivot) элемент, ниже которого в матрице следует заработать нули путем умножения текущей (той, где расположен ведущий элемент) строки матрицы на соответствующий коэффициент и вычитания ее из строки, в которой надо получить нули. Ведущий элемент временно хранится в переменной d. Если в ходе исключения он окажется равным нулю, то это означает, что исходная матрица вырождена. Вычисления в этом случае прекращаются и выдается сообщение с номером строки, в которой обнаружен факт вырожденности. Прямой ход осуществляется с помощью трех вложенных циклов. Внешний цикл — это пробег по диагональным элементам. Число повторений должно быть на единицу меньше числа строк, так как под последним диагональным элементом исключать нечего.

Второй цикл перебирает строки под ведущим элементом, поэтому число повторений зависит от номера текущей строки k. Третий внутренний цикл пробегает по столбцам выбранной в предыдущем цикле строки и изменяет элементы матрицы, включая и правую часть. Алгоритм не изменяет коэффициенты, стоящие ниже главной диагонали, так как они должны стать нулевыми и далее не используются. Поэтому индекс j, управляющий внутренним циклом, начинает изменяться с номера k+1 (номер столбца правее ведущего), и доходит до номера n (номера дополнительного столбца с правыми частями).

Алгоритм обратной подстановки для решения системы с верхней треугольной матрицей реализован следующим образом. Индекс k пробегает по всем строкам преобразованной верхней треугольной матрицы снизу вверх. При k<n–1 внутренний цикл вычисляет вклад уже найденных элементов вектора решений в текущий вычисляемый элемент x[k]. При k==n–1, то есть для последней строки, внутренний цикл не выполняется, так как не выполнено условие j>k, и x[n–1] вычисляется как a[n–1][n]/a[n–1][n–1]. Заметим, что в расширенной матрице элемент a[n–1][n] принадлежит вектору правых частей.