Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Расширенный алгоритм Евклида.doc
Скачиваний:
2
Добавлен:
25.09.2019
Размер:
128.51 Кб
Скачать

Расширенный рекурсивный алгоритм Евклида

Другой способ найти помимо НОД(a,b) и его представление в виде a·x+b·y – это дополнить рекурсивную реализацию алгоритма Евклида.

Procedure RecEuclid (a,b:Integer; Var d:Integer);

Var r:Integer;

Begin

If b=0 Then d:=a

Else Begin

r:=a Mod b;

RecEuclid(b,r,d);

End;

End;

Этот алгоритм, в принципе, выполняет те же вычисления, что и итеративный. Определяется цепочка остатков до наибольшего общего делителя. 2322, 654, 360, 294, 66, 30, 6, 0, при этом вся цепочка запоминается. Кроме того, в соответствии с логикой работы рекурсивных схем реализации осуществляется возврат к началу вычислений (выход из рекурсии). В данном случае «налегке», «в холостую». Вот здесь-то, на обратном пути, мы и «заставим» его работать.

Завершив прямой проход, процедура «смотрит» на два последних числа в цепочке. На b и r. Наибольший общий делитель d равен b. Выразим его через b и r: d=b·1+r·0.

Внимание – снова вопрос. Есть a=q∙b+r, 0≤r<b и известно представление d с помощью b и r: d=b·x/+r·y/. Как найти представление d с помощью a и b?

Ответ. Так как r=a-q∙b, то d=b·x/+r·y/=b·x/+(a-q∙b)·y/=a·y/+b·(x/-qy/),

или d=a·x+b·y, где

x = y/, y = x/-q∙y/.

Итак, нам известно, с чего начать обратный путь и как делать шаг по цепочке назад. По формулам выражаем d уже через пару предпоследних чисел в цепочке, продолжаем выходить из рекурсии до тех пор, пока не выразим d через первые два числа.

Пример. Пусть a=2322 и b=654. Строим таблицу (рис. 1.22) в два этапа. На первом – сверху вниз – находим частные и остатки от делений. На втором – снизу вверх – вычисляем множители x и y.

r

x

y

q

2322

654

3

360

1

294

1

66

4

30

2

6

5

0

Рис. 1.22. Пример вычисления представления d в виде a·x+b·y с помощью рекурсивной логики

В самую нижнюю строку автоматически заносим 1 и 0. Это очевидное представление наибольшего общего делителя d=6, с помощью 6 и 0: 6=6·1+0·0.

Заполняем вторую строку снизу. Значение x=0 просто переносим «по диагонали» из строки ниже. Вычисляем y=1-0·5=1. Это представление d с помощью 30 и 6: 6=30·0+6·1.

Определяем третью строку. Значение x=1 вновь берём «по диагонали» из строки ниже, а значение y=0-1·2=-2. Это представление d с помощью 66 и 30. 6=66·1+30·(-2).

«Всё выше и выше». В результате, выразим d через 2322 и 654. Как и в итеративной версии, НОД(2322,654)=6=2322·20+654·(-71).

Программная реализация имеет вид.

Procedure RecExEuclid (a,b:Integer; Var d,x,y:Integer);

Var r,q,x1,y1:Integer;

Begin

If b=0 Then Begin

d:=a;

x:=1; y:=0;

End

Else Begin

r:=a Mod b;

q:=a Div b;

RecExEuclid(b,r,d,x1,y1);

x:=y1;

y:=x1-y1*q;

End;

End;

Заметим, переменные r, q, x1 и y1 здесь совсем не обязательны. Процедура станет «легче», «сбросит» несколько строк. Но понять её уже будет сложнее.

Procedure RecExEuclid (a,b:Integer; Var d,x,y:Integer);

Begin

If b=0 Then Begin

d:=a;

x:=1; y:=0;

End

Else Begin

RecExEuclid(b,a Mod b,d,y,x);

y:=y-x*(a Div b);

End;

End;

Пересмотрим и ручные вычисления. Вернёмся к построению таблице (рис. 1.23). Одно не может не броситься в глаза. Столбец x практически совпадает со столбцом y. Зачем тогда его выписывать?

Рис. 1.23. Измененный вариант вычисления представления d в виде a·x+b·y

В две нижние клетки столбца y сразу помещаем 1 и 0. Заполняем третью снизу строку: y=1–0·5=1, затем четвёртую – y=0–1·2=-2, пятую – y=1–(–2)·4=9. Поднимаемся вверх и ведём вычисления по этому принципу. В результате, получаем искомые значения x и y – 20 и -71.