В этом листке мы будем реализовывать класс многочленов Poly, используемый для представления многочленов и операций над ними.
Как и в прошлом листке, при сдаче в тестирующую программу необходимо добавить после описания класса строку exec(open('input.txt').read()).
Создайте новый класс Poly с единственным атрибутом: _coeff — списком коэффициентов многочлена.
Конструктор __init__ на данном этапе может принимать только список чисел типов int или float.
Метод __repr__ должен возвращать строку, из которой можно создать в точности такой-же многочлен.
При этом нулевые старшие коэффициенты должны быть обрезаны (кроме многочлена нулевого многочлена).
Добавьте также константу X — многочлен Poly([0, 1]).
Доработайте конструктор __init__ так, чтобы он мог принимать следующие типы аргументов:
Без аргументов (Poly()). В таком случае создается многочлен степени 0 с единственным коэффициентом 0.
Один аргумент типа int, float. В этом случае создается многочлен степени 0 с одним коэффициентом;
Один аргумент — итерируемый объект, возвращающий элементы типа int, float (например, список, кортеж, range, map и т.п. ).
При этом нулевые старшие коэффициенты обрезаются.
Проверить, что объект является итерируемым, можно при помощи hasattr(объект, '__iter__') (только сначала убедитесь, что это
— не строка);
Доработайте конструктор __init__ так, чтобы он мог принимать следующие типы аргументов:
Один аргумент типа int, float. В этом случае создается многочлен степени 0 с одним коэффициентом;
Строка, содержащая коэффициенты многочлена типа int, float (от младшего к старшему) через пробел;
Многочлен (объект класса Poly). Конструктор должен создавать копию списка коэффициентов.
Один аргумент — итерируемый объект, возвращающий элементы типа int, float (например, список, кортеж, range, map и т.п. ). Проверить, что объект является итерируемым, можно при помощи hasattr(объект, '__iter__');
Без аргументов (Poly()). В таком случае создается многочлен степени 0 с единственным коэффициентом 0.
print(repr(Poly('1'))) print(repr(Poly('1 2 3'))) print(repr(Poly('1 2.34 5.67 0'))) A = Poly('1 2.34 5.67 0') B = Poly(A) print(A is B) print(A._coeff is B._coeff) print(A._coeff == B._coeff)
Реализуйте метод __str__, который будет выводить удобное для человека представление многочлена:
Одночлены в многочлене записываются от старшего к младшему с переменной x через знаки «+» и «-».
Одночлены, коэффициент при которых равен 0, пропускаются.
Между коэффициентом и переменной знаков нет, например: 2x.
Степень многочлена записывается в верхнем регистре, соответствующими символами Unicode (см. таблицу ниже), например, x¹⁰.
Если коэффициент отрицательный, то вместо знака «+» перед слагаемым пишется «-».
Пробелы ставятся только вокруг знаков «+» и «-», но если коэффициент перед старшим членом отрицательный, то между знаком и модулем коэффициента пробела нет.
Свободный член записывается без x⁰, вместо x¹ записывается x.
Коэффициенты, равные по модулю 1, не пишутся, например: - x². Исключением является свободный член, он пишется и в том случае, когда равен 1.
Если коэффициент имеет тип float, то округляется до 3 знаков после запятой, например: - 0.333x.
Если все коэффициенты многочлена равны 0, то он выводится в виде строки из одного символа “0”.
Да, мне кажется, что я уже достаточно думал над этой задачей
Чес-слово! :)
Нужно реализовать функцию, которая по степени и коэффициенту выведет строковое представление монома данной степени.
Для хранения юникод-символов можно использовать словарь {'0': chr(8304), ...}.
Далее создать список строковых представлений мономов.
У старшего коэффициента поправить знак (убрать + и побел перед минусом).
После чего склеить вместе.
Я не могу решить эту задачу
Я вообще не понимаю этого и не хочу задавать вопросы
Но я попробую к ней вернуться, честно!
Просто игнорируйте её и решайте дальше, начиная с 5-й задачи.
В качестве __str__ следующий код:
def__str__(e):
return (lambda f, g, i, j, l: (lambda k: '0'if f(k) == 1and k[0] == 0else (lambda b: ((lambda a: ((l if a.startswith(' + ') else'-') + a[3:]))(b(f(k) - 1, k[-1])) + l.join(b(h, k[h]) for h inrange(f(k) - 2, -1, -1))))(((lambda a, b: (l if b == 0else (' + 'if b.real >= 0else' - ') + (l if g(b) == 1and a > 0else i(j(g(b), 3)) iftype(b) == floatelse i(g(b))) + (l if a == 0else'x'if a == 1else'x' + l.join({'0': chr(8304), '1': chr(185), '2': chr(178), '3': chr(179), '4': chr(8308), '5': chr(8309), '6': chr(8310), '7': chr(8311), '8': chr(8312), '9': chr(8313)}[s] for s in i(a))))))))(e._coeff))(f=len, g=abs, i=str, j=round, l='')
Единственное ограничение: у вашего многочлена не должно быть ведущих нулей (кроме последнего), иначе метод будет работать неправильно.
Реализуйте методы __eq__, __ne__, __neg__, __pos__ и __bool__.
Метод __neg__ должен возвращать новый многочлен, равный минус текущему.
Метод __pos__ должен возвращать self.
Метод __bool__ должен возвращать False только для многочлена, равного нулю.
A = Poly(range(5)) B = Poly([0, 1, 2, 3, 4]) C = Poly(range(4)) print(+A) print(-A) print((+A) is A) print(-A is A) print(A == B) print(A == C) print(A != B) print(A != C) print(Poly(3) == 3)
4x⁴ + 3x³ + 2x² + x -4x⁴ - 3x³ - 2x² - x TrueFalseTrueFalseFalseTrueTrue
Реализуйте методы для сложения многочленов друг с другом, а также с числами типа int и float.
Кроме __add__ и __radd__ необходимо также реализовать метод __iadd__, который используется в выражениях (A += 2).
Метод __iadd__ должен модифицировать собственный набор коэффициентов и возвращать self.
В классе комплексных чисел мы не стали реализовывать этот метод, так как комплексные числа неизменяемы, при операции A += 2 в A попадает уже новое комплексное число.
Совет
Постарайтесь уменьшить дублирование кода.
Например, можно реализовать метод __iadd__, а в методах __add__ и __radd__ его вызывать (используя += или прямо .__iadd__()).
При ловком исполнении __add__, __radd__, __isub__, __sub__, __rsub__, __mul__, __rmul__ делаются используя эту идею за одну строчку (без маразма, лямбда функций и т.п.).
A = Poly(range(5)) B = Poly([1.23, 2.34, 0, -5]) C = Poly([0, 0, 0, 0, 0, 0, 2]) print(A + B) print(A + C) print(B + C) print(A + (-A)) print(A + B + C) print(3 + A) print(A + 3) print(2.1 + B) print(B + 2.1) A += 1 B += 1.23 D = C C += B + A print(C) print(D) print(C is D)
Реализуйте методы для вычитания многочленов и чисел.
A = Poly(range(5)) B = Poly([1.23, 2.34, 0, -5]) C = Poly([0, 0, 0, 0, 0, 0, 2]) print(A - B) print(A - C) print(B - C) print(A - (+A)) print(A - B + C) print(3 - A) print(A - 3) print(2.1 - B) print(B - 2.1) A -= 1 B -= 1.23 D = C C -= B - A print(C) print(D) print(C is D)
Реализуйте методы для умножения многочленов и чисел.
A = Poly(range(5)) B = Poly([1.23, 2.34, 0, -5]) C = Poly([0, 0, 0, 0, 0, 0, 2]) print(A * B) print(A * C) print(B * C) print(A * (+A)) print(A * B * C) print(3 * A) print(A * 3) print(2.1 * B) print(B * 2.1) A *= 1 B *= 1.23 D = C C *= B * A print(C) print(D) print(C is D) print( 7 * X*X*X*X*X*X*X*X*X*X - 3 * X*X*X*X*X + (X - 3) * (2 - X * 5 * X) )
Реализуйте методы для быстрого возведения в степень.
Показатель степени - целое неотрицательное число.
Должен быть определены операторы “**” для левого операнда типа Poly, правого операнда типа int (при этом неотрицательное).
Должен быть определен оператор “**=” для левого операнда типа Poly, правого операнда типа int.
A = Poly([1, 1]) B = Poly([2]) C = Poly([1, 0, 0, 0, 0, 0, 0, 0, 2.34, 0, 0, 0, -2]) print(A ** 0) print(A ** 1) print(A ** 2) print(A ** 10) print(B ** 100) print(C ** 3) D = C C **= 3print(C) print(D) print(C is D) print( 7 * X**10 - 3 * X**5 + (X - 3) * (2 - 5 * X**2) )
Реализуйте функцию вычисления значения выражения в точке x. Если P - объект класса Poly, x - объект типа int, float, то вычисление многочлена в точке x производится при помощи перегруженной операции P | x.
Для перегрузки операции P | x нужно определить метод __or__ класса Poly.
Левый операнд имеет тип Poly, правый операнд: тип int, float.
Значение многочлена в точке должно вычисляться по схеме Горнера.
Добавьте во все методы поддержку класса Fraction.
В методе __str__ выводите дроби со знаменателем, не равным 1 в скобках (3/4). Дроби, со знаменателем, равным 1 выводите как целое.
A = Poly((1, 1.2, Fraction(5, -2), 0, Fraction('-1.2'))) B = A ** 2 - 2 * A print(A) print(B)
Реализуйте деление многочленов с остатком.
Пусть даны два многочлена A и B. При делении многочлена A на многочлен B получается два многочлена Q (частное) и R (остаток) такие, что A = Q * B + R, при этом deg(R) < deg(B). Для нахождения частного и остатка используется алгоритм деления “в столбик”.
Необходимо реализовать метод __divmod__(self, other) - возвращает кортеж из двух элементов: частного и остатка. Для вызова используется divmod(a, b).
Если в процессе деления возникает деление целого числа на целое, то результат деления должен иметь тип Fraction.
Необходимо реализовать:
метод __divmod__(self, other) - возвращает кортеж из двух элементов: частного и остатка. Для вызова используется divmod(a, b).
метод __rdivmod__(self, other) - вызывается при делении числа на многочлен.
Должны быть определены операторы “//” и “%” для операндов типа Poly, int, float, Fraction при этом хотя бы один операнд имеет тип Poly.
Должен быть определен операторы “//=” и “%=” для левого операнда типа Poly, правого операнда типа Poly, int, float, Fraction.
A = Poly([1, 1]) ** 5 B = Poly([1, 1]) C = Poly([1, -1, 1]) print(A // B) print(B // A) print(A % C) print(C % A) A //= B print(A) A %= C print(A) print('({}) = ({}) * ({}) + ({})'.format(2, A, *divmod(2, A)))
O: Определение длины многочлена и доступ к коэффициентам
Необходимо реализовать функцию определение длины многочлена len(P) и возможности чтения и изменения коэффициентов по индексу P[i].
Для определения длины объекта необходимо определить метод __len__(self). Данный метод должен возвращать длину списка коэффициентов, т.е. степень многочлена + 1.
Для возможности чтения значения коэффициента многочлена P[i] необходимо определить метод P.__getitem__(self, i). Если значение i не является целым, необходимо генерировать исключение IndexError при помощи инструкции raise IndexError(). Исключение IndexError необходимо генерировать и в случае, когда i < 0.
Для возможности присваивания коэффициенту многочлена нового значения val необходимо определить метод P.__setitem__(self, i, val). При этом если i >= len(P) необходимо “расширить” список коэффициентов до нужного значения, при i < 0 необходимо генерировать исключение IndexError.
Необходимо реализовать операцию композиции многочленов: если P и Q - объекты класса Poly, то P(Q) должно возврашать объект класса Poly, являющийся композицией многочленов.
Для этого необходимо перегрузить определить метод __call__(self, x). Если P - объект класса Poly, то при использовании объекта P, как вызова функции P(x) будет вызван метод P.__call__(x).
Метод P.__call__(x) должен возвращать значение многочлена в точке x, если x является объектом классов int, float, Fraction; если же x является объектом класса Poly, то метод __call__ должен возвращать композицию многочленов.
A = Poly([1, 1]) B = A(A) print(B) print((A**2)(A**2)) print((A**10)(1))
Реализуйте метод rational_roots,
возвращающий упорядоченный по возрастанию список всех рациональных корней ненулевого многочлена.
Если какой-либо коэффициент имеет тип, отличный от int, Fraction, то необходимо взвести ошибку TypeError().
Реализуйте функцию pgcd(a, b), возвращающую НОД двух многочленов. Старший коэффициент НОДа должен быть равен 1.
Если какой-либо коэффициент имеет тип, отличный от int, Fraction, то необходимо взвести ошибку TypeError().