Лаб_02
.docx
МИНИСТЕРСТВО ЦИФРОВОГО РАЗВИТИЯ,
СВЯЗИ И МАССОВЫХ КОММУНИКАЦИЙ РОССИЙСКОЙ ФЕДЕРАЦИИ
ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ
«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М.А. БОНЧ-БРУЕВИЧА»
(СПбГУТ)
ФАКУЛЬТЕТ ИНФОКОММУНИКАЦИОННЫХ СЕТЕЙ И СИСТЕМ (ИКСС)
КАФЕДРА ЗАЩИЩЕННЫХ СИСТЕМ СВЯЗИ (ЗСС)
______________________________________________________________________________
Отчет
по лабораторной работе №2
«Нахождения наибольшего общего делителя НОД()»
Выполнили: студенты группы ИБС-32
Проверил:
доцент кафедры ЗСС к.т.н Кушнир Д.В.
Теоретическая часть
Нахождения наибольшего общего делителя НОД().
В криптографии важную роль играет теория чисел.
Некоторые задачи из теории чисел, используемые при построении криптографических преобразований:
I. Нахождение наибольшего общего делителя чисел a и b: НОД(a,b).
Один из путей решения – разложить каждое из чисел на множители и найти в двух разложениях максимальный совпадающий, однако такой подход является неэффективным (имеет экспоненциальную сложность).
Алгоритм Эвклида – нахождение НОД.
Алгоритм в общем виде: Найти: НОД(a,b) a =b *q1 + r1 0≤ri<b //q1-целое,r1-остаток от деления a на b * b =r1 *q2 + r2 0≤r2<r1 ………………………………
rn-3=rn-2 *qn-1 +rn-1 rn-2=rn-1 *qn +0 rn=0 Ответ: НОД(a,b)=rn-1 //ответ – последний ненулевой остаток.
* Примечание: в выражении a=b *q1 + r1 имеется ввиду, что производится деление числа а на b и вычисляется остаток r1 и количество целых q1.
Пример НОД(1234,54) 1234 = 54 *22 +46 54 = 46 * 1 + 8 46 = 8 * 5 + 6 8 = 6 * 1 + 2 6 = 2 * 3 + 0 Последний ненулевой остаток 2, т.е. НОД (1234,54)=2
Формализованное описание алгоритма Эвклида:
Алгоритм НОД(a,b) a>b
Начальные присвоения A=a; R=B=b;
В цикле выполняем:
a) R=остаток от деления A на B;
IF(R=0) B – ответ
b) A=B;
c) B=R;
Пример НОД(24;15)
A |
|
B |
|
q |
|
R |
24 |
|
15 |
|
|
|
|
24 |
= |
15 |
* |
1 |
+ |
9 |
15 |
= |
9 |
* |
1 |
+ |
6 |
9 |
= |
6 |
* |
1 |
+ |
3 |
6 |
= |
3 |
* |
2 |
+ |
0 |
Бинарный алгоритм Евклида
Бинарный алгоритм Евклида вычисления НОД оказывается более быстрым при реализации этого алгоритма на компьютере, поскольку использует двоичное представление чисел а и b.
Бинарный алгоритм Евклида основан на следующих свойствах наибольшего общего делителя (считаем, что 0 < b ≤ а):
если оба числа а и b четные, то НОД(a,b) = 2 · НОД(a/2 , b/2)
если число а нечетное, число b четное, то НОД(a, b) = НОД(а, b/2);
если оба числа а и b нечетные, а > b, то НОД(а, b) = НОД(а – b, b);
если а = b, то НОД(а, b) = а.
Формализованное описание алгоритма Бинарного алгоритма Евклида.
Вход: Целые числа a, b; 0 < b ≤ а.
Выход. d = HOД(a,b).
Положить g ← 1.
Пока оба числа а и b четные, выполнять а← a/2 , b ← b/2, g ← 2g до получения хотя бы одного нечетного значения а или b.
Положить u ← a, v ← b.
Пока u ≠ 0, выполнять следующие действия.
4.1. Пока u четное, полагать u ← u/2.
4.2. Пока v четное, полагать v ← v/2.
4.3. При u ≥ v положить: u ← u–v, в противном случае: v ← v–u.
Положить d ← gv.
Результат: d. Р
Пример («ручное» вычисление): НОД(88,52)
НОД(88,52) = 2*НОД(44,26) = 4*НОД(22,13) = 4*НОД(11,13) =
= 4*НОД(13-11,11) = 4*НОД(2,11) = 4*НОД(11-2,2) = 4*НОД(9,2) =
= 4*НОД(9-2,2) = 4*НОД(7,2) = 4*НОД(5,2) = 4*НОД(5-2,2) = 4*НОД(3,2) =
= 4*НОД(3-2,2) = 4*НОД(1,2) = 4*НОД(2-1,1)=4*НОД(1,1)=4
Решение
3 вариант:
Задание 1.
A = 26 B = 44
44 = 26*1 + 18
26 = 18*1 + 8
18 = 8*2 + 2
8 = 2*4 + 0
НОД = 2
Задание 2.
def gcd_euclid(a, b): while b: quotient = a // b remainder = a % b print(f"{a} = {b} * {quotient} + {remainder}") a, b = b, remainder print(f"НОД: {a}") return a a = int(input("Введите первое число: ")) b = int(input("Введите второе число: ")) gcd_euclid(a, b)
Введите первое число: 1111492
Введите второе число: 564422
1111492 = 564422 * 1 + 547070
564422 = 547070 * 1 + 17352
547070 = 17352 * 31 + 9158
17352 = 9158 * 1 + 8194
9158 = 8194 * 1 + 964
8194 = 964 * 8 + 482
964 = 482 * 2 + 0
НОД: 482
Задание 3.
НОД(44,26) = 2*НОД(22,13) = 2*НОД(11,13) =
= 2*НОД(13-11,11) = 2*НОД(2,11) = 2*НОД(11-2,2) = 2*НОД(9,2) =
= 2*НОД(9-2,2) = 2*НОД(7,2) = 2*НОД(5,2) = 2*НОД(5-2,2) = 2*НОД(3,2) =2*НОД(3-2,2) = 2*НОД(1,2) = 2*НОД(2-1,1)=2*НОД(1,1)=2
НОД: 2
Задание 4.
def gcd_binary(a, b): step = 1 if a == 0: print(f"НОД: {b}") return b if b == 0: print(f"НОД: {a}") return a shift = 0 while (a | b) & 1 == 0: a, b = a >> 1, b >> 1 shift += 1 while a & 1 == 0: a >>= 1 while b: while b & 1 == 0: b >>= 1 if a > b: a, b = b, a b -= a print(f"Шаг {step}: a = {a}, b = {b}") step += 1 gcd = a << shift print(f"НОД: {gcd}") return gcd a = int(input("Введите первое число: ")) b = int(input("Введите второе число: ")) gcd_binary(a, b)
Введите первое число: 1111492
Введите второе число: 564422
Шаг 1: a = 277873, b = 4338
Шаг 2: a = 2169, b = 275704
Шаг 3: a = 2169, b = 32294
Шаг 4: a = 2169, b = 13978
Шаг 5: a = 2169, b = 4820
Шаг 6: a = 1205, b = 964
Шаг 7: a = 241, b = 964
Шаг 8: a = 241, b = 0
НОД: 482
Вариант 16
Задание 1
a = 20
b = 12
20 = 12 * 1 + 8
12 = 8 * 1 + 4
8 = 4 * 2 + 0
НОД = 4
Задание 2
a = 1542844
b = 775042
Код программы:
def evklide(a, b): while b != 0: r = a%b q = a // b print (f"{a} = {q}*{b} + {r}") a = b b = r print(f"НОД равен {a}") num1 = int(input("Введите число 1: ")) num2 = int(input("Введите число 2: ")) evklide(num1, num2)
Вывод программы:
Введите число 1: 1542844
Введите число 2: 775042
1542844 = 1*775042 + 767802
775042 = 1*767802 + 7240
767802 = 106*7240 + 362
7240 = 20*362 + 0
НОД равен 362
Задание 3
НОД(20,12) = 2*НОД(10,6) = 4*НОД(5,3) =
= 4*НОД(5-3,3) = 4*НОД(2,3) = 4*НОД(3-2,2) = 4*НОД(2,1) =
= 4*НОД(2-1,1)=4*НОД(1,1)
НОД = 4
Задание 4
Код программы:
def binary_gcd_algorithm(a, b): if a == 0: return b, [(a, b, 0)] if b == 0: return a, [(a, b, 0)] g = 1 steps = [] while a % 2 == 0 and b % 2 == 0: a //= 2 b //= 2 g *= 2 steps.append((a, b, g)) u, v = a, b while u != 0: while u % 2 == 0: u //= 2 steps.append((u, v, g)) while v % 2 == 0: v //= 2 steps.append((u, v, g)) if u >= v: u -= v else: v -= u steps.append((u, v, g)) return g * v, steps num1 = int(input("Введите первое число: ")) num2 = int(input("Введите второе число: ")) result, intermediate_steps = binary_gcd_algorithm(num1, num2) print(f"НОД равен {result}") print("\nПромежуточные шаги:") for step in intermediate_steps: print(f"{step[0]} = {step[1]} + {step[2]} * 2^{step[2]}")
Вывод программы:
Введите первое число: 1542844
Введите второе число: 775042
Промежуточные шаги:
771422 = 387521 + 2 * 2^2
385711 = 387521 + 2 * 2^2
385711 = 1810 + 2 * 2^2
385711 = 905 + 2 * 2^2
384806 = 905 + 2 * 2^2
192403 = 905 + 2 * 2^2
191498 = 905 + 2 * 2^2
95749 = 905 + 2 * 2^2
94844 = 905 + 2 * 2^2
47422 = 905 + 2 * 2^2
23711 = 905 + 2 * 2^2
22806 = 905 + 2 * 2^2
11403 = 905 + 2 * 2^2
10498 = 905 + 2 * 2^2
5249 = 905 + 2 * 2^2
4344 = 905 + 2 * 2^2
2172 = 905 + 2 * 2^2
1086 = 905 + 2 * 2^2
543 = 905 + 2 * 2^2
543 = 362 + 2 * 2^2
543 = 181 + 2 * 2^2
362 = 181 + 2 * 2^2
181 = 181 + 2 * 2^2
0 = 181 + 2 * 2^2
НОД равен 362
