-
Notifications
You must be signed in to change notification settings - Fork 0
/
euklid.py
81 lines (64 loc) · 2.12 KB
/
euklid.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from copy import copy
from dataclasses import dataclass, field, asdict
from math import gcd
from typing import Iterator, Iterable
from tabulate import tabulate
@dataclass()
class Euclid(Iterable):
# Only kept for validation
_a: int = field(init=False)
_b: int = field(init=False)
x: int
y: int
q: int = field(init=False)
r: int = field(init=False)
u: int = 1
s: int = 0
v: int = 0
t: int = 1
def __post_init__(self) -> None:
if self.x <= 0 or self.y <= 0 or self.x == self.y:
raise ValueError("The numbers must not be 0, negative, or equal to one another")
self._a = self.x
self._b = self.y
self.q = self.x // self.y
self.r = self.x - self.q * self.y
def __iter__(self) -> Iterator['Euclid']:
return self
def __next__(self) -> 'Euclid':
if self._is_done():
self._assert_final()
raise StopIteration
self._shift()
self.assert_row()
return self
def _shift(self) -> None:
old: Euclid = copy(self)
self.x = old.y
self.y = old.r
self.q = self.x // self.y
self.r = self.x - self.q * self.y
self.u = old.s
self.s = old.u - old.q * old.s
self.v = old.t
self.t = old.v - old.q * old.t
def assert_row(self) -> None:
assert self.r == self.x % self.y
assert self.y == self.s * self._a + self.t * self._b
def _assert_final(self) -> None:
assert self.y == gcd(self._a, self._b)
if self.y == 1:
assert (self.t * self._b) % self._a == 1
def _is_done(self) -> bool:
return self.r == 0
def dict(self) -> dict:
"""Filter fields that start with a _"""
return {key: value for (key, value) in asdict(self).items() if not key.startswith("_")}
@staticmethod
def print_table(a: int, b: int):
euclid = Euclid(a, b)
rows = [euclid.dict()]
for row in euclid:
rows.append(row.dict())
print(tabulate(rows, headers="keys", showindex=True))
print(f"==> The GCD of {a} and {b} is {euclid.y}")