Multiply two polynomials (original) (raw)

Given two polynomials represented by two arrays, write a function that multiplies the given two polynomials. In this representation, each index of the array corresponds to the exponent of the variable(e.g. x), and the value at that index represents the coefficient of the term. For example, the array **A [] = [a, b, c, d] represents the polynomial **a + b* x 1 + c* x 2 + d* x 3 and B[] = [ a 1 , b 1 , c 1 ** ]**represents the polynomial **a 1 + b 1 * x 1 + c 1 * x 2. The goal is to compute the product of these two polynomials and return the resulting polynomial in the same array-based format.

**Example:

**Input: A[] = [5, 0, 10, 6]
B[] = [1, 2, 4]
**Output: [5, 10, 30, 26, 52, 24]
**Explanation:
The first input array represents "5 + 0x1 + 10x2 + 6x3"
The second array represents "1 + 2x1 + 4x2"
after Multiply both them we get "5 + 10x1 + 30x2 + 26x3 + 52x4 + 24x5"

Table of Content

[Naive Approach] Multiplication Using Nested Loops - O(n*m) Time and O( n + m) Space

one by one consider every term of the first polynomial and multiply it with every term of the second polynomial. Following is the algorithm of this simple method.

**Step by Step Approach:

#include #include using namespace std;

// A represents coefficients of first polynomial // B represents coefficients of second polynomial vector multiply(vector A,vector B){

int m = A.size(), n = B.size();

// Initialize the product polynomial vector prod(m+n-1,0);

// Multiply two polynomials term by term // Take ever term of first polynomial for (int i=0; i<m; i++){

 // Multiply the current term of first polynomial
 // with every term of second polynomial.
 for (int j=0; j<n; j++)
    prod[i+j] += A[i]*B[j];

}

return prod; }

// Driver program to test above functions int main() { // The following array represents polynomial 5 + 10x^2 + 6x^3 vector A = {5, 0, 10, 6};

// The following array represents polynomial 1 + 2x + 4x^2
vector<int> B = {1, 2, 4};

vector<int> prod = multiply(A, B);
 
for(auto it:prod){
    cout<<it<<" ";
}
return 0;

}

Java

class GfG { // A represents coefficients of first polynomial // B represents coefficients of second polynomial public static int[] multiply(int[] A, int[] B) { int m = A.length; int n = B.length; // Initialize the product polynomial int[] prod = new int[m + n - 1];

    // Multiply two polynomials term by term
    // Take ever term of first polynomial
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            // Multiply the current term of first polynomial
            // with every term of second polynomial
            prod[i + j] += A[i] * B[j];
        }
    }

    return prod;
}

public static void main(String[] args) {
    // The following array represents polynomial 5 + 10x^2 + 6x^3
    int[] A = {5, 0, 10, 6};

    // The following array represents polynomial 1 + 2x + 4x^2
    int[] B = {1, 2, 4};

    int[] result = multiply(A, B);

    for (int coeff : result) {
        System.out.print(coeff + " ");
    }
}

}

Python

A represents coefficients of first polynomial

B represents coefficients of second polynomial

def multiply(A, B): m = len(A) n = len(B)

# Initialize the product polynomial
prod = [0] * (m + n - 1)

# Multiply two polynomials term by term
# Take ever term of first polynomial
for i in range(m):
    for j in range(n):
        # Multiply the current term of first polynomial
        # with every term of second polynomial
        prod[i + j] += A[i] * B[j]

return prod

if name == "main": A = [5, 0, 10, 6] B = [1, 2, 4] result = multiply(A, B) print(" ".join(map(str, result)))

C#

using System;

class GfG{ // A represents coefficients of first polynomial // B represents coefficients of second polynomial static int[] Multiply(int[] A, int[] B){ int m = A.Length; int n = B.Length;

    // Initialize the product polynomial
    int[] prod = new int[m + n - 1];

    // Multiply two polynomials term by term
    // Take ever term of first polynomial
    for (int i = 0; i < m; i++){
        
        for (int j = 0; j < n; j++){
            
            // Multiply the current term of first polynomial
            // with every term of second polynomial
            prod[i + j] += A[i] * B[j];
        }
    }

    return prod;
}

static void Main(){
    
    int[] A = { 5, 0, 10, 6 };
    int[] B = { 1, 2, 4 };
    int[] result = Multiply(A, B);
    
    foreach (int coeff in result){
        
        Console.Write(coeff + " ");
    }
}

}

JavaScript

function multiply(A, B) {

let m = A.length;
let n = B.length;

// Initialize the product polynomial
let prod = new Array(m + n - 1).fill(0);

// Multiply two polynomials term by term
// Take ever term of first polynomial
for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
        
        // Multiply the current term of first polynomial
        // with every term of second polynomial
        prod[i + j] += A[i] * B[j];
    }
}

return prod;

}

// driver code let A = [5, 0, 10, 6]; let B = [1, 2, 4];

let result = multiply(A, B); console.log(result.join(" "));

`

**Time complexity: O(m x n), Where m and n is the size of the array A and B respectively.
**Auxiliary Space: O(m + n)

[Better Approach] Using Karatsuba algorithm (Divide and Conquer)

This Algorithm work only when size of both is equal, so to make it work we pad 0 at higher power in the small size array. Then splitting is done at the middle of the polynomial them recursively

Let the two given polynomials be A and B.

For simplicity, Let us assume that the given two polynomials are of same degree and have degree in powers of 2, i.e., n = 2i

The polynomial 'A' can be written as A0 + A1*xn/2
The polynomial 'B' can be written as B0 + B1*xn/2

For example 1 + 10x + 6x2 - 4x3 + 5x4 can be
written as (1 + 10x) + (6 - 4x + 5x2)*x2

A * B = (A0 + A1*xn/2) * (B0 + B1*xn/2)
= A0*B0 + A0*B1*xn/2 + A1*B0*xn/2 + A1*B1*xn
= A0*B0 + (A0*B1 + A1*B0)xn/2 + A1*B1*xn

Let us take another example with array inputs

A = [5,0,10,6] becomes A0 = [5,0] and A1 = [10,6]
B = [1,2,4] becomes B = [1, 2, 4, 0] becomes B0 = [1,2] and B1 = [4,0]

So the above divide and conquer approach requires 4 multiplications and O(n) time to add all 4 results. Therefore the time complexity is T(n) = 4T(n/2) + O(n). The solution of the recurrence is O(n2) which is the same as the above simple solution.
The idea is to reduce the number of multiplications to 3 and make the recurrence as T(n) = 3T(n/2) + O(n)

**How to reduce the **number of multiplications?
This requires a little trick similar to Strassen’s Matrix Multiplication. We do the following 3 multiplications. We recursively Compute the Three Products

The Karatsuba algorithm computes three intermediate products using recursive calls:

  1. z0 = A0 × B0 (This is the product of the lower halves of A and B).
  2. z2 = A1 × B1 ​ (This is the product of the upper halves of A and B).
  3. z1 = (A0+A1) × (B0+B1) − z0 − z2​ (This is a clever "middle term" that is computed using the sum of the two halves of the polynomials).

**In-Depth Explanation
Conventional polynomial multiplication uses 4 coefficient multiplications:

(ax + b)(cx + d) = acx2 + (ad + bc)x + bd

However, notice the following relation:

(a + b)(c + d) = ad + bc + ac + bd

The rest of the two components are exactly the middle coefficient for the product of two polynomials. Therefore, the product can be computed as:

(ax + b)(cx + d) = acx2 + ((a + b)(c + d) - ac - bd )x + bd

Hence, the latter expression has only three multiplications. So the time taken by this algorithm is T(n) = 3T(n/2) + O(n). The solution of the above recurrence is O(nLg3) which is better than O(n2).

C++ `

#include <bits/stdc++.h> using namespace std;

// Pads a polynomial with zeros to the specified length vector padPolynomial(const vector& poly, size_t targetSize) { vector padded = poly; while (padded.size() < targetSize) { padded.push_back(0); } return padded; }

// Karatsuba multiplication algorithm for polynomials vector multiply(vector& A, vector& B) { size_t n = max(A.size(), B.size());

// Round up n to the next power of 2
if (n & (n - 1)) {
    n = 1 << (static_cast<int>(log2(n)) + 1);
}

vector<int> a = padPolynomial(A, n);
vector<int> b = padPolynomial(B, n);

// Base case
if (n == 1) {
    return {a[0] * b[0]};
}

size_t half = n / 2;

// Divide the polynomials into halves
vector<int> aLow(a.begin(), a.begin() + half);
vector<int> aHigh(a.begin() + half, a.end());
vector<int> bLow(b.begin(), b.begin() + half);
vector<int> bHigh(b.begin() + half, b.end());

// Recursive call
vector<int> productLow = multiply(aLow, bLow);     
vector<int> productHigh = multiply(aHigh, bHigh);  

// Sum of parts
vector<int> aSum(half), bSum(half);
for (size_t i = 0; i < half; ++i) {
    aSum[i] = aLow[i] + aHigh[i];
    bSum[i] = bLow[i] + bHigh[i];
}

vector<int> productSum = multiply(aSum, bSum);

// Middle term: (aLow + aHigh) * (bLow + bHigh) - 
// productLow - productHigh
vector<int> productMiddle(productSum.size());
for (size_t i = 0; i < productSum.size(); ++i) {
    productMiddle[i] = productSum[i] - productLow[i] - productHigh[i];
}

// Combine results
vector<int> result(2 * n, 0);

for (size_t i = 0; i < productLow.size(); ++i) {
    result[i] += productLow[i];
}

for (size_t i = 0; i < productMiddle.size(); ++i) {
    result[half + i] += productMiddle[i];
}

for (size_t i = 0; i < productHigh.size(); ++i) {
    result[2 * half + i] += productHigh[i];
}

// Trim to actual size of result: A.size() + B.size() - 1
vector<int> finalResult;
size_t actualSize = A.size() + B.size() - 1;
for (size_t i = 0; i < actualSize; ++i) {
    finalResult.push_back(result[i]);
}

return finalResult;

}

int main() {

vector<int> A = {5, 0, 10, 6};
vector<int> B = {1, 2, 4};

vector<int> result = multiply(A, B);

// Output result
for (int coeff : result) {
    cout << coeff << " ";
}

return 0;

}

Java

import java.util.*;

public class KaratsubaPolynomial {

// Function to pad the polynomial to the desired size
static int[] pad_polynomial(int[] poly, int size) {
    int[] padded_poly = Arrays.copyOf(poly, size);
    return padded_poly;
}

// Karatsuba multiplication algorithm for polynomials
static int[] multiply(int[] A, int[] B) {
    int n = Math.max(A.length, B.length);

    // Pad the smaller polynomial with zeros to make
    // both have the same size
    if ((n & (n - 1)) != 0) {
        // If n is not a power of 2, round up to the next power of 2
        n = 1 << (int)(Math.log(n) / Math.log(2) + 1);
    }

    int[] A_padded = pad_polynomial(A, n);
    int[] B_padded = pad_polynomial(B, n);

    // If the size of the polynomials is 1, simply 
    // multiply the coefficients
    if (n == 1) {
        return new int[]{A_padded[0] * B_padded[0]};
    }

    int m = n / 2;

    // Split the polynomials into two halves
    int[] A0 = Arrays.copyOfRange(A_padded, 0, m);
    int[] A1 = Arrays.copyOfRange(A_padded, m, n);
    int[] B0 = Arrays.copyOfRange(B_padded, 0, m);
    int[] B1 = Arrays.copyOfRange(B_padded, m, n);

    // Recursively compute the three products
    int[] z0 = multiply(A0, B0);  // A0 * B0
    int[] z2 = multiply(A1, B1);  // A1 * B1

    // (A0 + A1) * (B0 + B1)
    int[] A0_plus_A1 = new int[m];
    int[] B0_plus_B1 = new int[m];
    for (int i = 0; i < m; ++i) {
        A0_plus_A1[i] = A0[i] + A1[i];
        B0_plus_B1[i] = B0[i] + B1[i];
    }
    int[] z1 = multiply(A0_plus_A1, B0_plus_B1);

    // Calculate the middle term: z1 - z0 - z2
    int[] middle_term = new int[z1.length];
    for (int i = 0; i < z1.length; ++i) {
        middle_term[i] = z1[i] - z0[i] - z2[i];
    }

    // Combine the results to get the final result
    int[] result = new int[2 * n];

    // Add z0 to the result
    for (int i = 0; i < z0.length; ++i) {
        result[i] += z0[i];
    }

    // Add middle_term * x^m to the result
    for (int i = 0; i < middle_term.length; ++i) {
        result[m + i] += middle_term[i];
    }

    // Add z2 * x^(2m) to the result
    for (int i = 0; i < z2.length; ++i) {
        result[2 * m + i] += z2[i];
    }

    // Final trimming
    int[] ans = new int[A.length + B.length - 1];
    for (int i = 0; i < ans.length; ++i) {
        ans[i] = result[i];
    }
    return ans;
}

public static void main(String[] args) {
    int[] A = {5, 0, 10, 6};
    int[] B = {1, 2, 4};

    int[] result = multiply(A, B);

    for (int val : result) {
        System.out.print(val + " ");
    }
}

}

Python

import math

Function to pad the polynomial to the desired size

def pad_polynomial(poly, size): padded_poly = poly[:] while len(padded_poly) < size: padded_poly.append(0) return padded_poly

Karatsuba multiplication algorithm for polynomials

def multiply(A, B): n = max(len(A), len(B))

# Pad the smaller polynomial with zeros to make both have the same size
if (n & (n - 1)) != 0:
    # If n is not a power of 2, round up to the next power of 2
    n = 1 << (math.floor(math.log2(n)) + 1)

A_padded = pad_polynomial(A, n)
B_padded = pad_polynomial(B, n)

# If the size of the polynomials is 1, simply multiply the coefficients
if n == 1:
    return [A_padded[0] * B_padded[0]]

m = n // 2

# Split the polynomials into two halves
A0 = A_padded[:m]
A1 = A_padded[m:]
B0 = B_padded[:m]
B1 = B_padded[m:]

# Recursively compute the three products
z0 = multiply(A0, B0)  # A0 * B0
z2 = multiply(A1, B1)  # A1 * B1

# (A0 + A1) * (B0 + B1)
A0_plus_A1 = [A0[i] + A1[i] for i in range(m)]
B0_plus_B1 = [B0[i] + B1[i] for i in range(m)]
z1 = multiply(A0_plus_A1, B0_plus_B1)

# Calculate the middle term: z1 - z0 - z2
middle_term = [z1[i] - z0[i] - z2[i] for i in range(len(z1))]

# Combine the results to get the final result
result = [0] * (2 * n)

# Add z0 to the result
for i in range(len(z0)):
    result[i] += z0[i]

# Add middle_term * x^m to the result
for i in range(len(middle_term)):
    result[m + i] += middle_term[i]

# Add z2 * x^(2m) to the result
for i in range(len(z2)):
    result[2 * m + i] += z2[i]

ans = result[:len(A) + len(B) - 1]
return ans

if name == "main": A = [5, 0, 10, 6] B = [1, 2, 4] result = multiply(A, B) print(" ".join(map(str, result)))

C#

using System;

class KaratsubaPolynomial { // Function to pad the polynomial to the desired size static int[] pad_polynomial(int[] poly, int size) { int[] padded_poly = new int[size]; for (int i = 0; i < poly.Length; i++) padded_poly[i] = poly[i]; return padded_poly; }

// Karatsuba multiplication algorithm for polynomials
static int[] multiply(int[] A, int[] B)
{
    int n = Math.Max(A.Length, B.Length);

    // Pad the smaller polynomial with zeros to make both have the same size
    if ((n & (n - 1)) != 0)
    {
        // If n is not a power of 2, round up to the next power of 2
        n = 1 << ((int)Math.Log(n, 2) + 1);
    }

    int[] A_padded = pad_polynomial(A, n);
    int[] B_padded = pad_polynomial(B, n);

    // If the size of the polynomials is 1, simply multiply the coefficients
    if (n == 1)
    {
        return new int[] { A_padded[0] * B_padded[0] };
    }

    int m = n / 2;

    // Split the polynomials into two halves
    int[] A0 = new int[m];
    int[] A1 = new int[m];
    int[] B0 = new int[m];
    int[] B1 = new int[m];

    Array.Copy(A_padded, 0, A0, 0, m);
    Array.Copy(A_padded, m, A1, 0, m);
    Array.Copy(B_padded, 0, B0, 0, m);
    Array.Copy(B_padded, m, B1, 0, m);

    // Recursively compute the three products
    int[] z0 = multiply(A0, B0);  // A0 * B0
    int[] z2 = multiply(A1, B1);  // A1 * B1

    // (A0 + A1) * (B0 + B1)
    int[] A0_plus_A1 = new int[m];
    int[] B0_plus_B1 = new int[m];
    for (int i = 0; i < m; ++i)
    {
        A0_plus_A1[i] = A0[i] + A1[i];
        B0_plus_B1[i] = B0[i] + B1[i];
    }

    int[] z1 = multiply(A0_plus_A1, B0_plus_B1);

    // Calculate the middle term: z1 - z0 - z2
    int[] middle_term = new int[z1.Length];
    for (int i = 0; i < z1.Length; ++i)
    {
        middle_term[i] = z1[i] - z0[i] - z2[i];
    }

    // Combine the results to get the final result
    int[] result = new int[2 * n];

    // Add z0 to the result
    for (int i = 0; i < z0.Length; ++i)
    {
        result[i] += z0[i];
    }

    // Add middle_term * x^m to the result
    for (int i = 0; i < middle_term.Length; ++i)
    {
        result[m + i] += middle_term[i];
    }

    // Add z2 * x^(2m) to the result
    for (int i = 0; i < z2.Length; ++i)
    {
        result[2 * m + i] += z2[i];
    }

    // Final trimming
    int[] ans = new int[A.Length + B.Length - 1];
    Array.Copy(result, 0, ans, 0, ans.Length);
    return ans;
}

static void Main()
{
    int[] A = { 5, 0, 10, 6 };
    int[] B = { 1, 2, 4 };

    int[] result = multiply(A, B);

    foreach (int val in result)
    {
        Console.Write(val + " ");
    }
}

}

JavaScript

// Function to pad the polynomial to the desired size function pad_polynomial(poly, size) { let padded_poly = poly.slice(); while (padded_poly.length < size) { padded_poly.push(0); } return padded_poly; }

// Karatsuba multiplication algorithm for polynomials function multiply(A, B) { let n = Math.max(A.length, B.length);

// Pad the smaller polynomial with zeros to make both have the same size
if ((n & (n - 1)) !== 0) {
    // If n is not a power of 2, round up to the next power of 2
    n = 1 << (Math.floor(Math.log2(n)) + 1);
}

let A_padded = pad_polynomial(A, n);
let B_padded = pad_polynomial(B, n);

// If the size of the polynomials is 1, simply multiply the coefficients
if (n === 1) {
    return [A_padded[0] * B_padded[0]];
}

let m = n / 2;

// Split the polynomials into two halves
let A0 = A_padded.slice(0, m);
let A1 = A_padded.slice(m);
let B0 = B_padded.slice(0, m);
let B1 = B_padded.slice(m);

// Recursively compute the three products
let z0 = multiply(A0, B0);  // A0 * B0
let z2 = multiply(A1, B1);  // A1 * B1

// (A0 + A1) * (B0 + B1)
let A0_plus_A1 = [];
let B0_plus_B1 = [];
for (let i = 0; i < m; i++) {
    A0_plus_A1.push(A0[i] + A1[i]);
    B0_plus_B1.push(B0[i] + B1[i]);
}
let z1 = multiply(A0_plus_A1, B0_plus_B1);

// Calculate the middle term: z1 - z0 - z2
let middle_term = [];
for (let i = 0; i < z1.length; i++) {
    middle_term.push(z1[i] - z0[i] - z2[i]);
}

// Combine the results to get the final result
let result = Array(2 * n).fill(0);

// Add z0 to the result
for (let i = 0; i < z0.length; i++) {
    result[i] += z0[i];
}

// Add middle_term * x^m to the result
for (let i = 0; i < middle_term.length; i++) {
    result[m + i] += middle_term[i];
}

// Add z2 * x^(2m) to the result
for (let i = 0; i < z2.length; i++) {
    result[2 * m + i] += z2[i];
}

let ans = result.slice(0, A.length + B.length - 1);
return ans;

}

// Driver Code let A = [5, 0, 10, 6]; let B = [1, 2, 4]; let result = multiply(A, B); console.log(result.join(" "));

`

**Time Complexity: O(n(log⁡23))≈O(n1.585), where n is the size of the input polynomial (or the next power of 2 greater than or equal to the size of the input arrays).
**Auxiliary Space: O(n), where n is the size of the input polynomial (or the next power of 2 greater than or equal to the size of the input arrays).

[Expected Approach] Fast Fourier Transform - O(n*log(n)) Time and O(n) Space

A(x) = a0 ​+ a1​x + a2x2 + ⋯ +an-1​xn-1

We assume, **without loss of generality, that the number of coefficients n is a **power of 2.
If it's not, we can simply **pad the polynomial with zeros to make the number of terms a power of 2. That is, for missing terms aixi , we just set ai =0.

The equation xn = 1 has exactly n distinct complex solutions, known as the **n-th roots of unity.
Each root is given by:

ω n,k **= e 2πi / n​ , for k=0,1,2,…,n−1

These roots lie evenly spaced on the **unit circle in the complex plane.
ω n​ n,1​ =e 2πi / n​

Then all the n-th roots of unity can be expressed as powers of ​ωn:

**ω n,k​ =(ω n ​) k

Discrete Fourier Transform (DFT)

The **Discrete Fourier Transform (DFT) of a polynomial A(x) or equivalently, of the coefficient vector (a0,a1,…,an−1​) is defined as the values of the polynomial evaluated at the n-th roots of unity:

**DFT(A) = [A(ω n,0 ),A(ω n,1 ),…,A(ω n,n−1 )]

In other words, you’re evaluating the polynomial A(x) at each complex point x=ωn,k for k=0 to n−1.

This transforms the polynomial from its **coefficient representation to its **value representation — a key step that enables fast multiplication via **pointwise product.

Inverse Discrete Fourier Transform (IDFT)

Just as the **Discrete Fourier Transform (DFT) converts a polynomial from its **coefficient form to its **value form, the **Inverse DFT (IDFT) performs the reverse:

**InverseDFT(y 0 ​,y 1 ​,…,y n−1​ ) = (a 0 ​,a 1 ​,…,a n−1 ​)

Let A(x) and B(x)B be two polynomials. Then:

****(A⋅B)(x) = A(x)⋅B(x)**

This implies that if we compute the **DFT of both polynomials, the element-wise (pointwise) multiplication of their transformed vectors:

DFT(A).DFT(B) == DFT(A⋅B)

Finally, the product of two polynomials A(x) and B(x) can be recovered by applying the **inverse Discrete Fourier Transform to the pointwise product of their DFTs:

**A⋅B = InverseDFT(DFT(A)⋅DFT(B))

C++ `

#include <bits/stdc++.h> using namespace std;

// Fast Fourier Transform implementation void fft(vector<complex>& coeffs, bool invert) { int n = coeffs.size(); if (n == 1) return;

// Split into even and odd indexed terms
vector<complex<double>> evenTerms(n / 2), oddTerms(n / 2);
for (int i = 0; 2 * i < n; ++i) {
    evenTerms[i] = coeffs[2 * i];
    oddTerms[i] = coeffs[2 * i + 1];
}

// Recursive FFT on both halves
fft(evenTerms, invert);
fft(oddTerms, invert);

// Calculate angle and root of unity
double pi = acos(-1);
double angle = 2 * pi / n * (invert ? -1 : 1);
complex<double> w(1), wn(cos(angle), sin(angle));

// Combine
for (int i = 0; 2 * i < n; ++i) {
    complex<double> t = w * oddTerms[i];
    coeffs[i] = evenTerms[i] + t;
    coeffs[i + n / 2] = evenTerms[i] - t;

    if (invert) {
        coeffs[i] /= 2;
        coeffs[i + n / 2] /= 2;
    }
    w *= wn;
}

}

// Function to multiply two polynomials using FFT vector multiply(vector& A, vector& B) { vector<complex> fftA(A.begin(), A.end()); vector<complex> fftB(B.begin(), B.end());

// Find next power of 2
int resultSize = 1;
while (resultSize < A.size() + B.size())
    resultSize <<= 1;

fftA.resize(resultSize);
fftB.resize(resultSize);

// Apply forward FFT to both
fft(fftA, false);
fft(fftB, false);

// Point-wise multiplication
for (int i = 0; i < resultSize; ++i)
    fftA[i] *= fftB[i];

// Inverse FFT to get back coefficients
fft(fftA, true);

// Round real parts to integers
vector<int> result(resultSize);
for (int i = 0; i < resultSize; ++i)
    result[i] = round(fftA[i].real());

// Remove trailing zeroes (optional)
while (result.size() >= (A.size() + B.size()))
    result.pop_back();

return result;

}

// Main driver function int main() { vector A = {5, 0, 10, 6};
vector B = {1, 2, 4};
vector product = multiply(A, B);

for (int coeff : product) {
    cout << coeff << " ";
}
cout << endl;

return 0;

}

Java

import java.util.*;

class GfG {

    // Complex number helper class
static class Complex {
    double real, imag;

    Complex(double r, double i) {
        real = r;
        imag = i;
    }

    Complex add(Complex o) {
        return new Complex(this.real + o.real, this.imag + o.imag);
    }

    Complex subtract(Complex o) {
        return new Complex(this.real - o.real, this.imag - o.imag);
    }

    Complex multiply(Complex o) {
        return new Complex(real * o.real - imag * o.imag, real 
                 * o.imag + imag * o.real);
    }

    Complex divide(double val) {
        return new Complex(real / val, imag / val);
    }
}
// Fast Fourier Transform implementation
static void fft(Complex[] coeffs, boolean invert) {
    int n = coeffs.length;
    if (n == 1) return;

    // Split into even and odd indexed terms
    Complex[] evenTerms = new Complex[n / 2];
    Complex[] oddTerms = new Complex[n / 2];
    for (int i = 0; 2 * i < n; ++i) {
        evenTerms[i] = coeffs[2 * i];
        oddTerms[i] = coeffs[2 * i + 1];
    }

    // Recursive FFT on both halves
    fft(evenTerms, invert);
    fft(oddTerms, invert);

    // Calculate angle and root of unity
    double pi = Math.acos(-1);
    double angle = 2 * pi / n * (invert ? -1 : 1);
    Complex w = new Complex(1, 0);
    Complex wn = new Complex(Math.cos(angle), Math.sin(angle));

    // Combine
    for (int i = 0; 2 * i < n; ++i) {
        Complex t = w.multiply(oddTerms[i]);
        coeffs[i] = evenTerms[i].add(t);
        coeffs[i + n / 2] = evenTerms[i].subtract(t);

        if (invert) {
            coeffs[i] = coeffs[i].divide(2);
            coeffs[i + n / 2] = coeffs[i + n / 2].divide(2);
        }
        w = w.multiply(wn);
    }
}

// Function to multiply two polynomials using FFT
static int[] multiply(int[] A, int[] B) {
    int n = 1;
    while (n < A.length + B.length) n <<= 1;

    Complex[] fftA = new Complex[n];
    Complex[] fftB = new Complex[n];

    for (int i = 0; i < n; ++i) {
        fftA[i] = new Complex(i < A.length ? A[i] : 0, 0);
        fftB[i] = new Complex(i < B.length ? B[i] : 0, 0);
    }

    // Apply forward FFT to both
    fft(fftA, false);
    fft(fftB, false);

    // Point-wise multiplication
    for (int i = 0; i < n; ++i)
        fftA[i] = fftA[i].multiply(fftB[i]);

    // Inverse FFT to get back coefficients
    fft(fftA, true);

    // Round real parts to integers
    int[] result = new int[n];
    for (int i = 0; i < n; ++i)
        result[i] = (int) Math.round(fftA[i].real);

    // Remove trailing zeroes (optional)
    int lastNonZero = result.length;
    while (lastNonZero >= A.length + B.length)
        lastNonZero--;

    return Arrays.copyOf(result, lastNonZero);
}

public static void main(String[] args) {
    int[] A = {5, 0, 10, 6};     
    int[] B = {1, 2, 4};         
    int[] product = multiply(A, B);

    for (int coeff : product) {
        System.out.print(coeff + " ");
    }
    System.out.println();
}

}

Python

import cmath

Fast Fourier Transform implementation

def fft(coeffs, invert=False): n = len(coeffs) if n == 1: return

# Split into even and odd indexed terms
even_terms = [coeffs[2 * i] for i in range(n // 2)]
odd_terms = [coeffs[2 * i + 1] for i in range(n // 2)]

# Recursive FFT on both halves
fft(even_terms, invert)
fft(odd_terms, invert)

# Calculate angle and root of unity
pi = cmath.pi
angle = 2 * pi / n * (-1 if invert else 1)
w = complex(1, 0)
wn = cmath.exp(complex(0, angle))

# Combine
for i in range(n // 2):
    t = w * odd_terms[i]
    coeffs[i] = even_terms[i] + t
    coeffs[i + n // 2] = even_terms[i] - t

    if invert:
        coeffs[i] /= 2
        coeffs[i + n // 2] /= 2
    w *= wn

Function to multiply two polynomials using FFT

def multiply(A, B): n = 1 while n < len(A) + len(B): n <<= 1

fftA = [complex(A[i] if i < len(A) else 0, 0) for i in range(n)]
fftB = [complex(B[i] if i < len(B) else 0, 0) for i in range(n)]

# Apply forward FFT to both
fft(fftA, False)
fft(fftB, False)

# Point-wise multiplication
for i in range(n):
    fftA[i] *= fftB[i]

# Inverse FFT to get back coefficients
fft(fftA, True)

# Round real parts to integers
result = [round(fftA[i].real) for i in range(n)]

# Remove trailing zeroes (optional)
while len(result) >= (len(A) + len(B)):
    result.pop()

return result

Main driver function

if name == "main": A = [5, 0, 10, 6]
B = [1, 2, 4]
product = multiply(A, B) print(*product)

C#

using System; using System.Collections.Generic;

struct Complex { public double Real, Imag;

public Complex(double real, double imag = 0) {
    Real = real;
    Imag = imag;
}

public static Complex operator +(Complex a, Complex b) =>
    new Complex(a.Real + b.Real, a.Imag + b.Imag);

public static Complex operator -(Complex a, Complex b) =>
    new Complex(a.Real - b.Real, a.Imag - b.Imag);

public static Complex operator *(Complex a, Complex b) =>
    new Complex(a.Real * b.Real - a.Imag * b.Imag,
                a.Real * b.Imag + a.Imag * b.Real);

public static Complex operator /(Complex a, double val) =>
    new Complex(a.Real / val, a.Imag / val);

public static Complex FromPolar(double r, double theta) =>
    new Complex(r * Math.Cos(theta), r * Math.Sin(theta));

public override string ToString() =>
    $"({Real} + {Imag}i)";

}

class GfG { static void FFT(Complex[] coeffs, bool invert) { int n = coeffs.Length; if (n == 1) return;

    Complex[] even = new Complex[n / 2];
    Complex[] odd = new Complex[n / 2];
    for (int i = 0; 2 * i < n; i++) {
        even[i] = coeffs[2 * i];
        odd[i] = coeffs[2 * i + 1];
    }

    FFT(even, invert);
    FFT(odd, invert);

    double angle = 2 * Math.PI / n * (invert ? -1 : 1);
    Complex w = new Complex(1, 0);
    Complex wn = Complex.FromPolar(1, angle);

    for (int i = 0; 2 * i < n; i++) {
        Complex t = w * odd[i];
        coeffs[i] = even[i] + t;
        coeffs[i + n / 2] = even[i] - t;
        if (invert) {
            coeffs[i] /= 2;
            coeffs[i + n / 2] /= 2;
        }
        w = w * wn;
    }
}

static int[] Multiply(int[] A, int[] B) {
    int n = 1;
    while (n < A.Length + B.Length) n <<= 1;

    Complex[] fa = new Complex[n];
    Complex[] fb = new Complex[n];
    for (int i = 0; i < n; i++) {
        fa[i] = i < A.Length ? new Complex(A[i]) : new Complex(0);
        fb[i] = i < B.Length ? new Complex(B[i]) : new Complex(0);
    }

    FFT(fa, false);
    FFT(fb, false);
    for (int i = 0; i < n; i++)
        fa[i] = fa[i] * fb[i];
    FFT(fa, true);

    int[] result = new int[n];
    for (int i = 0; i < n; i++)
        result[i] = (int)Math.Round(fa[i].Real);

    int last = result.Length - 1;
    while (last > 0 && result[last] == 0) last--;
    Array.Resize(ref result, last + 1);
    return result;
}

static void Main() {
    int[] A = { 5, 0, 10, 6 };
    int[] B = { 1, 2, 4 };

    int[] result = Multiply(A, B);
    foreach (int coeff in result) {
        Console.Write(coeff + " ");
    }
    Console.WriteLine();
}

}

JavaScript

// Fast Fourier Transform implementation function fft(coeffs, invert) { const n = coeffs.length; if (n === 1) return;

// Split into even and odd indexed terms
const evenTerms = new Array(n / 2);
const oddTerms = new Array(n / 2);
for (let i = 0; 2 * i < n; ++i) {
    evenTerms[i] = coeffs[2 * i];
    oddTerms[i] = coeffs[2 * i + 1];
}

// Recursive FFT on both halves
fft(evenTerms, invert);
fft(oddTerms, invert);

// Calculate angle and root of unity
const pi = Math.acos(-1);
const angle = 2 * pi / n * (invert ? -1 : 1);
let w = { re: 1, im: 0 };
const wn = { re: Math.cos(angle), im: Math.sin(angle) };

// Combine
for (let i = 0; 2 * i < n; ++i) {
    const t = { re: w.re * oddTerms[i].re - w.im * oddTerms[i].im, im: w.re * oddTerms[i].im + w.im * oddTerms[i].re };
    coeffs[i] = { re: evenTerms[i].re + t.re, im: evenTerms[i].im + t.im };
    coeffs[i + n / 2] = { re: evenTerms[i].re - t.re, im: evenTerms[i].im - t.im };

    if (invert) {
        coeffs[i].re /= 2;
        coeffs[i].im /= 2;
        coeffs[i + n / 2].re /= 2;
        coeffs[i + n / 2].im /= 2;
    }
    w = { re: w.re * wn.re - w.im * wn.im, im: w.re * wn.im + w.im * wn.re };
}

}

// Function to multiply two polynomials using FFT function multiply(A, B) { let n = 1; while (n < A.length + B.length) n <<= 1;

const fftA = new Array(n);
const fftB = new Array(n);

// Initialize FFT arrays with coefficients
for (let i = 0; i < n; ++i) {
    fftA[i] = { re: i < A.length ? A[i] : 0, im: 0 };
    fftB[i] = { re: i < B.length ? B[i] : 0, im: 0 };
}

// Apply forward FFT to both
fft(fftA, false);
fft(fftB, false);

// Point-wise multiplication
for (let i = 0; i < n; ++i) {
    fftA[i] = { re: fftA[i].re * fftB[i].re - fftA[i].im * fftB[i].im, im: fftA[i].re * fftB[i].im + fftA[i].im * fftB[i].re };
}

// Inverse FFT to get back coefficients
fft(fftA, true);

// Round real parts to integers
const result = new Array(n);
for (let i = 0; i < n; ++i) {
    result[i] = Math.round(fftA[i].re);
}

// Remove trailing zeroes (optional)
while (result.length >= (A.length + B.length)) {
    result.pop();
}

return result;

}

// Main driver function let A = [5, 0, 10, 6];
let B = [1, 2, 4];
let product = multiply(A, B); console.log(product.join(" "));

`

**Time Complexity: O(n log n), where n is the size of the next power of 2 greater than or equal to the sum of the sizes of the input polynomials.
**Auxiliary Space: O(n), where n is the size of the next power of 2 greater than or equal to the sum of the sizes of the input polynomials.