Бинарный алгоритм нахождения НОД (алгоритм Евклида)

Вычислить наибольший общий делитель двух целых чисел.

Дополнительные свойства
Вычисления производятся на основе следующих свойств НОД:
1. НОД(2m,2n) = 2 НОД(m ,n);
2. НОД(2m,2n+1) = НОД(m,2n+1);
3. НОД(-m,n) = НОД(m,n).

Алгоритм
1. НОД(0, n) = n; НОД(m, 0) = m;
2. Если m, n чётные, тогда НОД(m, n) = 2 * НОД(m / 2, n / 2).
3. Если m чётное, тогда НОД(m, n) = НОД(m / 2, n).
4. Если n чётное, тогда НОД(m, n) = НОД(m, n / 2).
5. Если m, n нечётные и m > n, тогда НОД(m, n) = НОД(m - n, n).
6. Если m, n нечётные и m < n, тогда НОД(m, n) = НОД(n - m, m).
7. Если m = n, тогда НОД(m, n) = m;

Ограничение алгоритма
Верен для множества целых неотрицательных чисел.

Реализация
Реализация на языке C++:

#include "iostream"
 
using namespace std;
 
 
int gcd(int u, int v);
 
 
int main()
{
	int u;
	int v;
 
	cout << "Numbers should lay in [0; MAXINT] interval." << endl;
 
	cout << "Enter 1st number: " << endl; 
	cin >> u;
 
	if (u < 0)
	{
		cout << "Incorrect value." << endl;
		cout << "Press any key to exit." << endl;
 
                system("PAUSE");
 
		exit(1);
	}
 
	cout << "Enter 2nd number: " << endl; 
	cin >> v;
 
	if (v < 0)
	{
		cout << "Incorrect value." << endl;
		cout << "Press any key to exit." << endl;
 
                system("PAUSE");
 
		exit(2);
	}
 
	cout << "Greatest common dividor is: " << gcd(u, v) << endl;
 
	system("PAUSE");
 
	return 0;
}
 
int gcd(int u, int v)
{
	int shift;
 
	/* НОД(0, n) = n; НОД(m, 0) = m. */
	if (u == 0 || v == 0)
	    return u | v;
 
	/* Если m, n чётные, тогда НОД(m, n) = 2 * НОД(m / 2, n / 2).
 
           Пусть shift := lg K, где K наибольшая степень 2 такая, что оба числа 
           целиком делятся на 2 в степени K. */
	for (shift = 0; ((u | v) & 1) == 0; ++shift) 
        {
            u >>= 1;
            v >>= 1;
        }
 
	// Если m чётное, тогда НОД(m, n) = НОД(m / 2, n).
        while ((u & 1) == 0)
	    u >>= 1;
 
	/* Далее считается, что u нечетное. */
        do 
        {
	    while ((v & 1) == 0)  /* Если n чётное, тогда НОД(m, n) = НОД(m, n / 2). */
	        v >>= 1;
 
            /* Далее считается, что u и v нечетные. Следовательно, u - v четно.
                Пусть u = min(u, v), v = (u - v) / 2. */
	    if (u < v) /* Если m, n нечётные и m < n, тогда НОД(m, n) = НОД(n - m, m). */
            {
	        v -= u;
            } 
        else /* Если m, n нечётные и m > n, тогда НОД(m, n) = НОД(m - n, m). */
	{
	    int diff = u - v;
            u = v;
            v = diff;
        }
 
        v >>= 1;
     } 
     while (v != 0);
 
     return u << shift;
 }

Пример работы программы
Numbers should lay in [0; MAXINT] interval.
Enter 1st number:
20456
Enter 2nd number:
5218
Greatest common dividor is: 2

Анализ алгоритма
Алгоритм использует:
- арифметические операции сложения и вычитания;
- операции побитового сравнения и сдвига.

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

Ключевые слова: 
бинарный алгоритм нахождения НОД, бинарный алгоритм Евклида, наибольший общий делитель
ВложениеРазмер
www.opita.net_GCD.rar5.34 кб