
Алгоритмы / 10.2 Алгоритм факторизации, основанный на полном переборе
.doc
Доклад на тему:
«Алгоритм факторизации, основанный на полном переборе»
Выполнил:
Литвинов Михаил
Б06-02
Алгоритм, основанный на полном переборе.
Данный алгоритм является адаптацией наиболее простого способа факторизации числа для параллельного вычисления. Он достаточно неэффективен, и потому может использоваться только как пример решения задач с помощью параллельного программирования, но не как реально работающий метод факторизации числа.
Пусть дано некоторое число N. Для его факторизации будет проводиться попытка его деления на все возможные числа от 2 до корня из N. Если делитель не будет найден, то, значит, число N – простое.
Распараллеливание этой задачи будет производиться следующим образом: изначально каждый процесс получает свой номер и общее количество потоков. Далее в каждом процессе происходит вычисление его нижней (корень из N, умноженный на номер процесса и делённый на их число) и верхней (то же самое, но к номеру процесса прибавляем единицу) границ, а затем — перебор всех чисел из заданного диапазона. В конце работы, после барьерной синхронизации, каждый процесс возвращает главному количество найденных делителей их массив.
Код:
#include <mpi.h>
#include <NTL/ZZ.h>
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
// Макрос для подключения NTL
NTL_CLIENT
int main(int argc, char *argv[])
{
int size, rank;
MPI_Init(&argc, &argv);
// Узнаём число процессов
MPI_Cоmm_size(MPI_COMM_WORLD, &size);
// И номер текущего процесса
MPI_Cоmm_rank(MPLCOMIVLWORLD, &rank);
// и число для факторизации
long N;
if (rank ==0)
{
// Ввод — только для корневого процессора
cin >> N;
}
// Рассылаем число остальным процессорам
MPI_Bcast(&N, 1, MPI_LONG, O, MPI_COMM_WORLD);
long low_bound, high_bound;
// Вычисляем верхнюю и нижнюю границы
low_bound = (long)(floor(sqrt((double)N))*(double)rank/(double)size);
high_bound = (long)(floor(sqrt((double)N))*(double)(rank+1)/(double)size);
if (rank == (size-1))
{
high_bound++;
}
PrimeSeq seq;
// Инициализируем генератор простых чисел
seq.reset (10w_b0und);
vector<long>result;
long X;
do
{
X = seq.next();
// Пока не переберём всё множество
if (X!=0 && X< high_bоund)
{
if(N %X==0)
{ // Проверяем, является ли Х делителем
result.push_back(X); // Если да, добавляем его
}
}
}
while (X!=0 && X< high_bound);
// Ожидаем завершения вычислений всеми процессорами
1\IPI_Barrier(MPI_COMM.WORLD);
// Сводим результат воедино
long res_count = result.size();
long temp_value;
MPI_Status status;
if (rank == 0 )
{
// Корневой процесс принимает данные от всех остальных
for (int i = 1; i < size; i++)
{
MPI_Recv(&res_count, 1, MPLLONG, i, 0, MPI_COMM_WORLD,
&status);
for (int j = 0; j < res_count; j++)
{
MPI_Recv(&temp_va1ue, 1, MPLLONG, i, 0, MPI_COMM_WORLD,
&status);
// И добавляет их в свой вектор делителей
result.push_back(temp_va1ue);
else
{
// Передача данных
// Отправляем число найденных делителей
MPI_Send(&res_count, 1, MPLLONG, O, 0, MPI_COMM_WORLD);
for (int j = 0; j < res_count; j++)
{
// Отправляем делители по-одному
temp_va1ue = resu1t[j];
MPI_Send(&temp.Value, 1, MPLLONG, 0, 0, MPLCOMMNVORLD);
}
}
// Выводим найденные делители
if (rank == 0)
{
for (vector<long> ::iterator t = resu1t.begin(); t <resu1t.end(); ++t)
{
cout << *t << " ";
}
cout << endl;
}
// Завершаем работу программы
MPLFinalize();
return 0;
Пример:
Факторизуем число 1073 с использованием 3 процессов:
Целая часть корня: 32
Диапазоны: [2-11][12-21][22-32] (с округлением вверх, 0, 1 не считается)
№0 |
число |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
|
вернёт |
остаток |
1 |
2 |
1 |
3 |
5 |
2 |
1 |
2 |
3 |
6 |
|
|
|
№1 |
число |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
|
вернёт |
остаток |
5 |
7 |
9 |
8 |
1 |
2 |
11 |
9 |
13 |
2 |
|
|
|
№2 |
число |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
вернёт |
остаток |
17 |
15 |
17 |
23 |
7 |
20 |
9 |
0 |
23 |
19 |
17 |
1; [29] |
Результат — 1073 сложное число, кратное 29 и, следовательно, 37
Временная сложность.
Как несложно заметить, для факторизации числа N необходимо N^(1/2) операций деления, или N^(1/2)/p на каждом из p процессоров.