As a school assignment, I am supposed to create a program in C# that multiplies two polynomials using FFT over a finite field.
My finite field of choice would be Zp (all operations modulo p, the elements are {0,...,p - 1} ). I realized the p has to be large enough so that the factors in the resulting polynomial are not changed by the modulo operation.
Finding the nth primitive root of unity is easy for small n(in a corresponding finite field). However, I needed to find it for n = 220. I practically needed only this one as computing it for all the lower powers of 2 is done by squaring. I tried to write a simple program that would compute it(using the fact that there is 2r th root of unity in the finite field Zc*2r + 1), ran it for a pretty long time and it didn t finish. So I tried to Google something and only found a table of primitive nth roots for n = 2k for k = 0..30 in the field Z70383776563201 and used it. Of course when I used longint, it resulted in overflow and therefore, wrong answers. So I started using the BigInteger structure from the System.Numerics namespace. This is where I am, having a correct algorithm that is extremely slow:
private static List<BigInteger> FFT(List<BigInteger> input, BigInteger Omega)
{
if (input.Count == 1)
{
return new List<BigInteger>() { input[0] };
}
else
{
List<BigInteger> evenInput = new List<BigInteger>();
for (int i = 0; i < input.Count; i += 2)
{
evenInput.Add(input[i]);
}
List<BigInteger> oddInput = new List<BigInteger>();
for (int i = 1; i < input.Count; i += 2)
{
oddInput.Add(input[i]);
}
List<BigInteger> even = FFT(evenInput, (Omega * Omega));
List<BigInteger> odd = FFT(oddInput, (Omega * Omega));
BigInteger[] outputArr = new BigInteger[input.Count];
int count = 0;
for (int i = 0; i < input.Count / 2; i++)
{
outputArr[i] = (even[i] + BigInteger.Pow(Omega, i) * odd[i]);
outputArr[i + input.Count / 2] = (even[i] - BigInteger.Pow(Omega, i) * odd[i]);
count += 2;
}
List<BigInteger> output = new List<BigInteger>();
for (int i = 0; i < count; i++)
{
output.Add(outputArr[i] % finiteField);
}
return output;
}
}
I know that creating all the lists doesn t help the speed, but the main problem is the BigInteger structure of course.(I tried basically the same code with System.Numerics.Complex structure and it was as fast as it should be) The modulo operation takes extremely long, so I know I have to go back to longint. The problem is finding the primitive nth root of unity. I don t know if it s even possible to use the 220 th primitive root of unity with longint without having to worry about overflow. If not, for which n can I use longint and thus have a fast algorithm?
Is there a way of computing the primitive roots for large n faster? Maybe someone knows of a table of precomputed primitive roots in finite fields? Or should I consider using other finite fields? This is the only kind I know of. I have been searching for quite a long time and didn t come across anything useful. I have been told by the teacher that this area is well documented, but it doesn t seem to be the case.