diff --git a/hw2.py b/hw2.py new file mode 100644 index 0000000..c15a1df --- /dev/null +++ b/hw2.py @@ -0,0 +1,121 @@ +import sys +import ast +import operator +from fractions import gcd + +class Polynomial(): + def __init__(self, lst, mod): + super().__init__() + self.poly = list(map(lambda x: x % mod, lst)) + self.mod = mod + self.normalize() + def normalize(self): + while self.poly and self.poly[-1] == 0: + self.poly.pop() + + def arithm(self, p1, p2, op): + len_p1, len_p2= len(p1.poly), len(p2.poly) + res = [0] * max(len_p1, len_p2) + if len_p1 > len_p2: + for _ in range(len_p1-len_p2): + p2.poly.append(0) + else: + for _ in range(len_p2-len_p1): + p1.poly.append(0) + + for i in range(len(res)): + res[i] = op(p1.poly[i], p2.poly[i]) % self.mod + return Polynomial(res, self.mod) + + def __add__(self, p2): + return self.arithm(self, p2, operator.add) + + def __sub__(self, p2): + return self.arithm(self, p2, operator.sub) + + def __mul__(self, p2): + res = [0]*(len(self.poly)+len(p2.poly)-1) + for i, x1 in enumerate(self.poly): + for j, x2 in enumerate(p2.poly): + res[i+j] += x1 * x2 % self.mod + return Polynomial(res, self.mod) + + def __truediv__(self, p2): + p1 = self + m = self.mod + + if len(p1.poly) < len(p2.poly): + return p1 + + if len(p2.poly) == 0: + raise ZeroDivisionError + + divisor_coeff = p2.poly[-1] + divisor_exp = len(p2.poly) - 1 + while len(p1.poly) >= len(p2.poly): + max_coeff_p1 = p1.poly[-1] #wspolczynnik przy najwyzszej potedze + try: + tmp_coeff = modDiv(max_coeff_p1, divisor_coeff, m) + except ZeroDivisionError as e: + raise e + + tmp_exp = len(p1.poly)-1 - divisor_exp + '''tmp to pomocniczy wielomian o reprezentacji [0, 0, .., c^n], gdzie c^n to + mnożnik w danym kroku algorytmu dzielenia w słupku. + Następnie mnożymy go z wielomianem-dzielnikiem (p2) i + odejmujemy (sub) od wielomianu-dzielnej (p1)''' + tmp = [] + for i in range(tmp_exp): + tmp.append(0) + tmp.append(tmp_coeff) + sub = Polynomial(tmp, m) * p2 + p1 = p1 - sub + p1.normalize() #obcinamy zbędne zera dopisane do wielomianu podczas odejmowania + return Polynomial(p1.poly, m) + + def poly_gcd(self, p2): + p1 = self + try: + divisible = p2 + except ZeroDivisionError as e: + raise e + if p2.poly == []: + return p1 + return p2.poly_gcd(p1 / p2) + +def modDiv(a, b, m): # a*b^-1 (mod m) + if gcd(b, m) != 1: + raise ZeroDivisionError + else: + return (a * modinv(b, m)) % m + +#rozszerzony algorytm euklidesa +def egcd(a, b): + if a == 0: + return (b, 0, 1) + else: + g, y, x = egcd(b % a, a) + return (g, x - (b // a) * y, y) + +def modinv(a, m): + g, x, y = egcd(a, m) + return x % m + +def main(): + n, p1, p2 = int(sys.argv[1]), ast.literal_eval(sys.argv[2]), ast.literal_eval(sys.argv[3]) + P1 = Polynomial(p1, n) + P2 = Polynomial(p2, n) + mul = (P1 * P2).poly + try: + div = (P1 / P2).poly + except ZeroDivisionError as e: + div = e + try: + gcd = P1.poly_gcd(P2).poly + except ZeroDivisionError as e: + gcd = e + print([mul, div, gcd]) + + +if __name__ == '__main__': + main() \ No newline at end of file