this module implements a single indeterminate polynomials class with some basic operations reference https en wikipedia orgwikipolynomial the coefficients should be in order of degree from smallest to largest p polynomial2 1 2 3 p polynomial2 1 2 3 4 traceback most recent call last valueerror the number of coefficients should be equal to the degree 1 polynomial addition p polynomial2 1 2 3 q polynomial2 1 2 3 p q 6x2 4x 2 polynomial subtraction p polynomial2 1 2 4 q polynomial2 1 2 3 p q 1x2 polynomial negation p polynomial2 1 2 3 p 3x2 2x 1 polynomial multiplication p polynomial2 1 2 3 q polynomial2 1 2 3 p q 9x4 12x3 10x2 4x 1 evaluates the polynomial at x p polynomial2 1 2 3 p evaluate2 17 p polynomial2 1 2 3 printp 3x2 2x 1 p polynomial2 1 2 3 p 3x2 2x 1 returns the derivative of the polynomial p polynomial2 1 2 3 p derivative 6x 2 returns the integral of the polynomial p polynomial2 1 2 3 p integral 1 0x3 1 0x2 1 0x checks if two polynomials are equal p polynomial2 1 2 3 q polynomial2 1 2 3 p q true checks if two polynomials are not equal p polynomial2 1 2 3 q polynomial2 1 2 3 p q false the coefficients should be in order of degree from smallest to largest p polynomial 2 1 2 3 p polynomial 2 1 2 3 4 traceback most recent call last valueerror the number of coefficients should be equal to the degree 1 polynomial addition p polynomial 2 1 2 3 q polynomial 2 1 2 3 p q 6x 2 4x 2 polynomial subtraction p polynomial 2 1 2 4 q polynomial 2 1 2 3 p q 1x 2 polynomial negation p polynomial 2 1 2 3 p 3x 2 2x 1 polynomial multiplication p polynomial 2 1 2 3 q polynomial 2 1 2 3 p q 9x 4 12x 3 10x 2 4x 1 evaluates the polynomial at x p polynomial 2 1 2 3 p evaluate 2 17 p polynomial 2 1 2 3 print p 3x 2 2x 1 p polynomial 2 1 2 3 p 3x 2 2x 1 returns the derivative of the polynomial p polynomial 2 1 2 3 p derivative 6x 2 returns the integral of the polynomial p polynomial 2 1 2 3 p integral 1 0x 3 1 0x 2 1 0x checks if two polynomials are equal p polynomial 2 1 2 3 q polynomial 2 1 2 3 p q true checks if two polynomials are not equal p polynomial 2 1 2 3 q polynomial 2 1 2 3 p q false
from __future__ import annotations

from collections.abc import MutableSequence


class Polynomial:
    def __init__(self, degree: int, coefficients: MutableSequence[float]) -> None:
        
        if len(coefficients) != degree + 1:
            raise ValueError(
                "The number of coefficients should be equal to the degree + 1."
            )

        self.coefficients: list[float] = list(coefficients)
        self.degree = degree

    def __add__(self, polynomial_2: Polynomial) -> Polynomial:
        

        if self.degree > polynomial_2.degree:
            coefficients = self.coefficients[:]
            for i in range(polynomial_2.degree + 1):
                coefficients[i] += polynomial_2.coefficients[i]
            return Polynomial(self.degree, coefficients)
        else:
            coefficients = polynomial_2.coefficients[:]
            for i in range(self.degree + 1):
                coefficients[i] += self.coefficients[i]
            return Polynomial(polynomial_2.degree, coefficients)

    def __sub__(self, polynomial_2: Polynomial) -> Polynomial:
        
        return self + polynomial_2 * Polynomial(0, [-1])

    def __neg__(self) -> Polynomial:
        
        return Polynomial(self.degree, [-c for c in self.coefficients])

    def __mul__(self, polynomial_2: Polynomial) -> Polynomial:
        
        coefficients: list[float] = [0] * (self.degree + polynomial_2.degree + 1)
        for i in range(self.degree + 1):
            for j in range(polynomial_2.degree + 1):
                coefficients[i + j] += (
                    self.coefficients[i] * polynomial_2.coefficients[j]
                )

        return Polynomial(self.degree + polynomial_2.degree, coefficients)

    def evaluate(self, substitution: float) -> float:
        
        result: int | float = 0
        for i in range(self.degree + 1):
            result += self.coefficients[i] * (substitution**i)
        return result

    def __str__(self) -> str:
        
        polynomial = ""
        for i in range(self.degree, -1, -1):
            if self.coefficients[i] == 0:
                continue
            elif self.coefficients[i] > 0:
                if polynomial:
                    polynomial += " + "
            else:
                polynomial += " - "

            if i == 0:
                polynomial += str(abs(self.coefficients[i]))
            elif i == 1:
                polynomial += str(abs(self.coefficients[i])) + "x"
            else:
                polynomial += str(abs(self.coefficients[i])) + "x^" + str(i)

        return polynomial

    def __repr__(self) -> str:
        
        return self.__str__()

    def derivative(self) -> Polynomial:
        
        coefficients: list[float] = [0] * self.degree
        for i in range(self.degree):
            coefficients[i] = self.coefficients[i + 1] * (i + 1)
        return Polynomial(self.degree - 1, coefficients)

    def integral(self, constant: float = 0) -> Polynomial:
        
        coefficients: list[float] = [0] * (self.degree + 2)
        coefficients[0] = constant
        for i in range(self.degree + 1):
            coefficients[i + 1] = self.coefficients[i] / (i + 1)
        return Polynomial(self.degree + 1, coefficients)

    def __eq__(self, polynomial_2: object) -> bool:
        
        if not isinstance(polynomial_2, Polynomial):
            return False

        if self.degree != polynomial_2.degree:
            return False

        for i in range(self.degree + 1):
            if self.coefficients[i] != polynomial_2.coefficients[i]:
                return False

        return True

    def __ne__(self, polynomial_2: object) -> bool:
        
        return not self.__eq__(polynomial_2)