diff --git a/src/analysis/Polynomial.hpp b/src/analysis/Polynomial.hpp
index 4d9941996e8379d2aed73d368d8d75a4a55f7b13..252db7b8deab35c3aa5991c03a74e6aa28469a0e 100644
--- a/src/analysis/Polynomial.hpp
+++ b/src/analysis/Polynomial.hpp
@@ -9,6 +9,7 @@ class Polynomial
  private:
   using Coefficients = TinyVector<N + 1, double>;
   Coefficients m_coefficients;
+  static_assert((N >= 0), "Polynomial degree must be non-negative");
 
  public:
   PUGS_INLINE
@@ -25,10 +26,12 @@ class Polynomial
     return m_coefficients;
   }
 
-  PUGS_INLINE
-  constexpr bool
-  operator==(const Polynomial<N>& q) const
+  template <size_t M>
+  PUGS_INLINE constexpr bool
+  operator==(const Polynomial<M>& q) const
   {
+    if (M != N)
+      return false;
     if (m_coefficients != q.coefficients()) {
       return false;
     }
@@ -42,22 +45,55 @@ class Polynomial
     return not this->operator==(q);
   }
 
-  PUGS_INLINE
-  constexpr Polynomial<N>
-  operator+(const Polynomial<N>& q) const
+  template <size_t M>
+  PUGS_INLINE constexpr Polynomial<std::max(M, N)>
+  operator+(const Polynomial<M>& Q) const
   {
-    TinyVector<N + 1> sum_coefs = m_coefficients + q.coefficients();
-    Polynomial<N> S(sum_coefs);
-    return S;
+    Polynomial<std::max(M, N)> P;
+    if constexpr (M > N) {
+      P.coefficients() = Q.coefficients();
+      for (size_t i = 0; i <= N; ++i) {
+        P.coefficients()[i] += coefficients()[i];
+      }
+    } else {
+      P.coefficients() = coefficients();
+      for (size_t i = 0; i <= M; ++i) {
+        P.coefficients()[i] += Q.coefficients()[i];
+      }
+    }
+    return P;
   }
 
-  PUGS_INLINE
-  constexpr Polynomial<N>
-  operator-(const Polynomial<N>& q) const
+  template <size_t M>
+  PUGS_INLINE constexpr Polynomial<std::max(M, N)>
+  operator-(const Polynomial<M>& Q) const
+  {
+    Polynomial<std::max(M, N)> P;
+    if constexpr (M > N) {
+      P.coefficients() = -Q.coefficients();
+      for (size_t i = 0; i <= N; ++i) {
+        P.coefficients()[i] += coefficients()[i];
+      }
+    } else {
+      P.coefficients() = coefficients();
+      for (size_t i = 0; i <= M; ++i) {
+        P.coefficients()[i] -= Q.coefficients()[i];
+      }
+    }
+    return P;
+  }
+
+  template <size_t M>
+  PUGS_INLINE constexpr Polynomial<M + N> operator*(const Polynomial<M>& Q) const
   {
-    TinyVector<N + 1> diff_coefs = m_coefficients - q.coefficients();
-    Polynomial<N> D(diff_coefs);
-    return D;
+    Polynomial<M + N> P;
+    P.coefficients() = zero;
+    for (size_t i = 0; i <= N; ++i) {
+      for (size_t j = 0; j <= M; ++j) {
+        P.coefficients()[i + j] += coefficients()[i] * Q.coefficients()[j];
+      }
+    }
+    return P;
   }
 
   PUGS_INLINE
@@ -112,47 +148,89 @@ class Polynomial
     return Polynomial<N + 1>{coefs};
   }
 
+  PUGS_INLINE
+  constexpr friend double
+  integrate(const Polynomial<N>& P, const double& xinf, const double& xsup)
+  {
+    Polynomial<N + 1> Q = primitive(P);
+    return (Q(xsup) - Q(xinf));
+  }
+
+  PUGS_INLINE
+  constexpr friend auto
+  derivative(const Polynomial<N>& P)
+  {
+    if constexpr (N == 0) {
+      return Polynomial<0>(0);
+    } else {
+      TinyVector<N> coefs;
+      for (size_t i = 0; i < N; ++i) {
+        coefs[i] = double(i + 1) * P.coefficients()[i + 1];
+      }
+      return Polynomial<N - 1>(coefs);
+    }
+  }
+
   PUGS_INLINE
   constexpr friend std::ostream&
   operator<<(std::ostream& os, const Polynomial<N>& P)
   {
     //    os << "P(x) = ";
     bool all_coef_zero = true;
-    for (size_t i = N; i > 1; --i) {
+    if (N == 0) {
+      os << P.coefficients()[0];
+      return os;
+    }
+    if (N != 1) {
+      if (P.coefficients()[N] != 0.) {
+        if (P.coefficients()[N] < 0.) {
+          os << "- ";
+        }
+        if (P.coefficients()[N] != 1 && P.coefficients()[N] != -1) {
+          os << std::abs(P.coefficients()[N]);
+        }
+        os << "x^" << N;
+        all_coef_zero = false;
+      }
+    }
+    for (size_t i = N - 1; i > 1; --i) {
       if (P.coefficients()[i] != 0.) {
+        if (P.coefficients()[i] > 0.) {
+          os << " + ";
+        } else if (P.coefficients()[i] < 0.) {
+          os << " - ";
+        }
         if (P.coefficients()[i] != 1 && P.coefficients()[i] != -1) {
           os << std::abs(P.coefficients()[i]);
         }
         os << "x^" << i;
-        if (P.coefficients()[i - 1] > 0.)
-          os << " + ";
-        else
-          os << " - ";
         all_coef_zero = false;
-      } else {
-        os << " ";
       }
     }
     if (P.coefficients()[1] != 0.) {
+      if (P.coefficients()[1] > 0. && N != 1) {
+        os << " + ";
+      } else if (P.coefficients()[1] < 0.) {
+        os << " - ";
+      }
       if (P.coefficients()[1] != 1 && P.coefficients()[1] != -1) {
         os << std::abs(P.coefficients()[1]);
       }
       os << "x";
-      if (P.coefficients()[0] > 0.)
-        os << " + ";
-      else if (P.coefficients()[0] < 0.)
-        os << " - ";
       all_coef_zero = false;
-    } else {
-      os << " ";
     }
-    if (P.coefficients()[0] != 0. || all_coef_zero)
+    if (P.coefficients()[0] != 0. || all_coef_zero) {
+      if (P.coefficients()[0] > 0.) {
+        os << " + ";
+      } else if (P.coefficients()[0] < 0.) {
+        os << " - ";
+      }
       os << std::abs(P.coefficients()[0]);
+    }
     return os;
   }
 
-  PUGS_INLINE
-  constexpr Polynomial(const TinyVector<N + 1>& coefficients) noexcept : m_coefficients{coefficients} {}
+  PUGS_INLINE constexpr Polynomial(const TinyVector<N + 1>& coefficients) noexcept : m_coefficients{coefficients} {}
 
   PUGS_INLINE
   constexpr Polynomial(TinyVector<N + 1>&& coefficients) noexcept : m_coefficients{coefficients} {}
diff --git a/tests/test_Polynomial.cpp b/tests/test_Polynomial.cpp
index 214be6ca85555730783975514172c0bfa7edc1a5..b5570d9dee27d3d182003f6120e17db013bc3acc 100644
--- a/tests/test_Polynomial.cpp
+++ b/tests/test_Polynomial.cpp
@@ -9,10 +9,12 @@
 #include <analysis/Polynomial.hpp>
 
 // Instantiate to ensure full coverage is performed
+template class Polynomial<0>;
 template class Polynomial<1>;
 template class Polynomial<2>;
 template class Polynomial<3>;
 template class Polynomial<4>;
+template class Polynomial<5>;
 
 // clazy:excludeall=non-pod-global-static
 
@@ -26,15 +28,20 @@ TEST_CASE("Polynomial", "[analysis]")
   {
     Polynomial<2> P({2, 3, 4});
     Polynomial<2> Q({2, 3, 4});
+    Polynomial<2> S({2, 3, 5});
 
     REQUIRE(P == Q);
+    REQUIRE(P != S);
   }
   SECTION("addition")
   {
     Polynomial<2> P({2, 3, 4});
     Polynomial<2> Q({-1, -3, 2});
     Polynomial<2> S({1, 0, 6});
+    Polynomial<3> T({0, 3, 1, -2});
+    Polynomial<3> U({2, 6, 5, -2});
     REQUIRE(S == (P + Q));
+    REQUIRE((T + P) == U);
   }
   SECTION("difference")
   {
@@ -42,6 +49,9 @@ TEST_CASE("Polynomial", "[analysis]")
     Polynomial<2> Q({3, 4, 5});
     Polynomial<2> D({-1, -1, -1});
     REQUIRE(D == (P - Q));
+    Polynomial<3> R({2, 3, 4, 1});
+    REQUIRE(D == (P - Q));
+    REQUIRE((P - R) == Polynomial<3>({0, 0, 0, -1}));
   }
   SECTION("product_by_scalar")
   {
@@ -50,6 +60,12 @@ TEST_CASE("Polynomial", "[analysis]")
     REQUIRE(M == (P * 3));
     REQUIRE(M == (3 * P));
   }
+  SECTION("product")
+  {
+    Polynomial<2> P({2, 3, 4});
+    Polynomial<3> Q({1, 2, -1, 1});
+    REQUIRE(Polynomial<5>({2, 7, 8, 7, -1, 4}) == (P * Q));
+  }
   SECTION("evaluation")
   {
     Polynomial<2> P({2, -3, 4});
@@ -67,4 +83,23 @@ TEST_CASE("Polynomial", "[analysis]")
     Polynomial<3> R({0, 2, -3. / 2, 4. / 3});
     REQUIRE(Q == R);
   }
+  SECTION("integrate")
+  {
+    Polynomial<2> P({2, -3, 3});
+    double xinf   = -1;
+    double xsup   = 1;
+    double result = integrate(P, xinf, xsup);
+    REQUIRE(result == 6);
+  }
+  SECTION("derivative")
+  {
+    Polynomial<2> P({2, -3, 3});
+    Polynomial<1> Q = derivative(P);
+    REQUIRE(Q == Polynomial<1>({-3, 6}));
+
+    Polynomial<0> P2(3);
+
+    Polynomial<0> R(0);
+    REQUIRE(derivative(P2) == R);
+  }
 }