A computer-algebra teaching tool needs polynomials with integer coefficients that behave like numbers. Write a class Poly(coeffs=()), where coeffs lists the coefficients from the constant term upwards: Poly([1, 0, 3]) is 3x^2 + 1. Trailing zeros mean nothing (Poly([2, 0, 0]) == Poly([2])), and Poly() is the zero polynomial.
repr(p)isPoly([...])without trailing zeros:Poly([1, 0, 3]),Poly([]).str(p)is the usual form, highest power first:"3x^3 - 3x^2 + x - 1". A coefficient of1or-1is not written except in the constant term,x^1is writtenx, the first term has a leading-if it is negative, the others are joined with" + "or" - ", and the zero polynomial is"0".p + q,p - q,p * q,-pandp ** n(for a whole numbern >= 0) work, and so do mixes with integers on either side:2 - p,3 * p,p + 1.p == qcompares the polynomials, and a constant polynomial equals that integer:Poly([5]) == 5. Equal values have equal hashes, so{Poly([5]), 5}has one element.p(v)evaluatespat an integerv; ifvis itself aPoly, the result is the polynomialp(v(x)).p[k]is the coefficient ofx^k(0beyond the degree),p.degreeis the highest power with a non-zero coefficient (-1for the zero polynomial), andbool(p)isFalseonly for the zero polynomial.p.derivative()returns the derivative.divmod(p, q),p // qandp % qdivide with remainder, so thatp == q * (p // q) + p % qwith(p % q).degree < q.degree. The divisor's highest coefficient must be1or-1(otherwiseValueError), and dividing by zero raisesZeroDivisionError.
The tests write x for Poly([0, 1]), so that they can build polynomials such as 3 * x ** 2 + 1 (define x = Poly([0, 1]) after your class to try the same). The setup's raises(fn, *args) returns the name of the exception a call raises (or None).
Examples
Input: p, q = Poly([1, 0, 3]), Poly([-1, 1])
str(p), str(q), str(p * q), p(2), str(p(q)), repr(p - p)
Output: ('3x^2 + 1', 'x - 1', '3x^3 - 3x^2 + x - 1', 13, '3x^2 - 6x + 4', 'Poly([])')
Input: [str(r) for r in divmod(x ** 3 - 1, x - 1)], str(2 - x), (x + 1) ** 3 == x ** 3 + 3 * x ** 2 + 3 * x + 1
Output: (['x^2 + x + 1', '0'], '-x + 2', True)
Constraints
- Coefficients are integers (possibly huge); degrees up to
300. - Every operation returns a new
Poly; operands never change.
Goals
- Implement arithmetic operators, including the reflected ones, so polynomials and integers mix freely
- Make objects callable, and let one `__call__` both evaluate and compose
- Keep a canonical internal form so that equality, hashing and printing agree