Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

[ООП] / Лекции / Zao_2009_Paral_3

.doc
Скачиваний:
18
Добавлен:
07.02.2016
Размер:
33.28 Кб
Скачать

2

Лабораторная работа № 3

Параллельное вычисление произведения матриц

Цель: Изучить один из методов распараллеливания умножения матриц.

Теоретические сведения

Решение многих научно-технических задач связано с необходимостью выполнения всевозможных матричных операций. Несмотря на рост мощности и быстродействия вычислительной техники, матричные преобразования могут занять основное время решения задачи, причем, в случае матриц большой размерности (например, 10000 х 10000 и больше) решение может длиться от нескольких часов до нескольких дней. Поэтому задачи такого класса решают с помощью параллельных и векторных ЭВМ. Для этого разрабатываются специальные алгоритмы, позволяющие распараллелить и векторизовать матричные операции.

В данной работе приводится алгоритм метода внутренних произведений, заключающийся в том, что каждый элемент результирующей матрицы можно представить как скалярное произведение вектора-строки первой матрицы на соответствующий вектор-столбец второй матрицы, т.е. произведение двух матриц Аmn и Вnq есть третья матрица Сmq, элементы которой определяются по формуле:

, i=1,2,…,m; j=1,2,…,q.

Напомним, что количество столбцов матрицы Аmn должно совпадать с количеством строк матрицы Вnq.

Вычисление этих скалярных произведений можно выполнять независимо друг от друга. Следовательно, если имеется число процессоров, равное числу элементов результирующей матрицы, то эти элементы можно вычислять параллельно. В реальных задачах, конечно, не выделяют по процессору на каждую операцию умножения. В зависимости от метода умножения и вычислительной мощности процессоров, каждому из них отводится задача вычисления либо строки, либо столбца, либо блока результирующей матрицы. В нашем случае лишь демонстрируется возможность распараллеливания умножения матриц в предельном случае. Этот алгоритм можно назвать мелкозернистым в отличие от среднезернистых, в которых вычисляются более крупные элементы матрицы (строки, столбцы, блоки).

В нашей работе параллельные процессоры имитируются потоками, которые создаются как производные от класса TThread пакета Borland C++ Builder.

Порядок выполнения

В Borland C++ Builder создайте проект консольного приложения (File|New| New Item|Console Applicaion). Этот проект будет состоять из основного модуля с телом функции main(), модуля описания глобальных переменных, модуля, содержащего описания класса (потока), который порожден (наследуется) от предопределенного класса TThread. Этот поток должен выполнять вычисление элемента результирующей матрицы.

Исходные матрицы необходимо описать таким образом, чтобы они были доступны во всех модулях (т.е. были глобальными). Для этого создайте новый модуль (File|New Unit) и поместите описание двумерного массива:

float A[M][K], B[K][N], C[M][N];

В заголовочном файле этого модуля объявите массивы внешними и поместите определения констант M, N, K ‑ размерностей массивов:

const K=10, M=10, N=10;

extern float A[M][K], B[K][N], C[M][N];

Создайте класс потока, который вычисляет скалярное произведение i-й строки матрицы A на j-й столбец матрицы B и сохраняет результат в C[i][j]. Для этого выберите в репозитории (File|New вкладка New Item) опцию Thread Object. В появившемся диалоговом окне введите название нового класса потока (например, TVectMul). Этот класс должен в функции Execute() содержать вычисление скалярного произведения i-й строки матрицы A на j-й столбец матрицы B, например

for(int k=0;k<K;k++)

C[i][j]=C[i][j]+A[i][k]*B[k][j];

Индексы i и j для номеров строк и столбцов матриц необходимо описать как приватные (закрытые) члены класса TVectMul.

Модифицируйте конструктор класса TvectMul() таким образом, чтобы при создании потока ему передавались номера строк и столбцов, которые в теле конструктора присваиваются членам класса i и j.

Создайте папку для проекта и сохраните все модули проекта. Это необходимо, чтобы файлы модулей получили свои имена. Следите за тем, чтобы файлы проекта были вместе в одной папке.

С помощью директивы препроцессора #include включите имя заголовочного файла, содержащего описания матриц, во все модули (*.cpp) и имя заголовочного файла с описанием класса в главный модуль проекта.

В функции main() главного модуля необходимо определить двумерный массив указателей для экземпляров класса TVectMul. Перед запуском (созданием) дочерних потоков инициализируйте массивы A[][] и B[][] при помощи циклов какими-либо значениями. Можно также произвести инициализацию при описании массивов (более наглядный и удобный способ).

Класс TVectMul вычисляет элемент результирующей матрицы С[i][j], следовательно необходимо запустить M*N экземпляров этого класса, передав каждому из них через вызов конструктора соответствующие i и j. Перед выводом результирующей матрицы С в главном потоке необходимо дождаться завершения работы потоков с помощью метода WaitFor() каждого из потоков. В конце программы не забудьте уничтожить экземпляры класса с помощью вызовов деструктора Free() для каждого потока.

Сохраните, скомпилируйте и запустите вашу программу. Проверьте корректность полученного результата. В отчете приведите тексты файлов с описанием и реализацией класса и текст главной функции main().

Контрольные вопросы

  1. Дайте определение ускорения параллельного алгоритма?

  2. Перечислите известные методы умножения матриц (по материалам лекций)?

  3. Какова степень параллелизма метода умножения матриц, реализованного в данном задании?

  4. Как реализовать умножение матрицы на вектор на параллельных процессорах?

  5. Как реализовать умножение матрицы на вектор на векторном процессоре?

  6. Для чего используется в программе данного задания метод WaitFor()?

  7. Существует ли необходимость синхронизировать вычисления элементов результирующей матрицы в методе внутренних произведений?

Параллельное программирование.

Соседние файлы в папке Лекции