/// <summary> /// Return multiplication of two polynoms using nonrecursive FFT /// </summary> /// <param name="p">First polynom</param> /// <param name="q">Second polynom</param> /// <returns>p * q</returns> public static Polynom operator *(Polynom p, Polynom q) { p = p.Clone(); q = q.Clone(); p.Trim(); q.Trim(); //set rank of mul int count = p.Count + q.Count - 1; if (p.Count == 0 || q.Count == 0) { throw new ArgumentException("Polynom must have at least one member."); } // So FFT returns polynom with bigger rank while (p.Count < count) { p.Add(0); p = p.ComplementWithNulls(); } while (q.Count < count) { q.Add(0); q = q.ComplementWithNulls(); } // Nonrecursive FFT Polynom p_vals = FFT.NonrecursiveFFT(p); Polynom q_vals = FFT.NonrecursiveFFT(q); Polynom r_vals = new Polynom(count).ComplementWithNulls(); count = r_vals.Count; for (int i = 0; i < count; i++) { Complex a = p_vals[i]; Complex b = q_vals[i]; r_vals[i] = a * b; } Polynom ret = FFT.NonrecursiveFFT(r_vals, true) / count; ret.Trim(); return(ret); }
static void TestWithShortPolynoms() { Polynom p, q, r; // Example 1 p = new Polynom((Complex)(-2)); // -2 q = new Polynom(15, 0, 0); // 15 + 0x + 0x^2 r = p * q; Console.WriteLine("Example {0}:\np =\n{1}\nq =\n{2}\np*q =\n{3}", 1, p, q, r); // Example 2 p = new Polynom(Complex.ImaginaryOne); // i q = new Polynom((Complex)3); // 3 r = p * q; Console.WriteLine("Example {0}:\np =\n{1}\nq =\n{2}\np*q =\n{3}", 2, p, q, r); // Example 3 p = new Polynom(1, 3); // 1 + 3x q = new Polynom(-2, 1); // -2 + x r = p * q; Console.WriteLine("Example {0}:\np =\n{1}\nq =\n{2}\np*q =\n{3}", 3, p, q, r); // Example 4 // The same result in WolframAlpha: // http://www.wolframalpha.com/input/?i=%28%282%2B4i%29+%2B+%282%2B8i%29x+%2B+%282%2B3i%29x%5E2%29+*+%282+%2B+%287+%2B+3i%29x%29 p = new Polynom(new Complex(2, 4), new Complex(2, 8), new Complex(2, 3)); q = new Polynom(new Complex(2, 0), new Complex(7, 3)); r = p * q; Console.WriteLine("Example {0}:\np =\n{1}\nq =\n{2}\np*q =\n{3}", 4, p, q, r); // Example 5 // In this case the rank of the result is not pow of 2 p = new Polynom(1, 2); q = new Polynom(1, 2, 3, 4, 5); r = p * q; Console.WriteLine("Example {0}:\np =\n{1}\nq =\n{2}\np*q =\n{3}", 4, p, q, r); }
/// <summary> /// /// </summary> /// <param name="p">Polynom. Must have pow of 2 member. Maybe you can use .ComplementWithNulls()</param> /// <param name="reversed">If true, the method will make reversed FFT (interpolation)</param> /// <returns></returns> public static Polynom NonrecursiveFFT(Polynom p, bool reversed = false) { int layersCount = (int)Math.Ceiling(Math.Log(p.Count, 2)); if (1 << layersCount != p.Count) { throw new ArgumentException("Polynom must have pow of 2 members. Maybe you want to use .ComplementWithNulls() methdo."); } //Permuts coefficients of p so they would suit the coefficients in the last layer of FFT Polynom new_p = new Polynom(p.Count); for (int i = 0; i < p.Count; i++) { int pom_i = i; int new_i = 0; int s = p.Count / 2; for (int l = 0; l < layersCount; l++) { if (pom_i % 2 == 1) { pom_i--; new_i += s; } pom_i /= 2; s /= 2; } new_p[new_i] = p[i]; } p = new_p; for (int layer = 1; layer <= layersCount; layer++) // { int nodeSize = 1 << layer; int nodeCount = p.Count / nodeSize; //division is integer Complex omega = ComplexUtils.GetSqrtOfOne(nodeSize); if (reversed) { omega = 1 / omega; } new_p = new Polynom(p.Count); for (int nodeI = 0; nodeI < nodeCount; nodeI++) { Complex x = 1; for (int i = 0; i < nodeSize / 2; i++) { Complex c1 = p[nodeI * nodeSize + i]; Complex c2 = p[nodeI * nodeSize + i + nodeSize / 2]; new_p[nodeI * nodeSize + i] = c1 + x * c2; new_p[nodeI * nodeSize + i + nodeSize / 2] = c1 - x * c2; x *= omega; } } p = new_p; //Uncomment to see how the algorithm works //Console.WriteLine("Layer {0}:", layer); //Console.WriteLine(p); //Console.WriteLine(); } return(p); }