source: git/ntl/src/FFT.c @ 33a041

spielwiese
Last change on this file since 33a041 was 09da99, checked in by Hans Schönemann <hannes@…>, 21 years ago
*hannes: NTL- 5.3.1 git-svn-id: file:///usr/local/Singular/svn/trunk@6910 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 8.5 KB
Line 
1
2
3#include <NTL/FFT.h>
4
5#include <NTL/new.h>
6
7NTL_START_IMPL
8
9long NumFFTPrimes = 0;
10
11long *FFTPrime = 0;
12long **RootTable = 0;
13long **RootInvTable = 0;
14long **TwoInvTable = 0;
15double *FFTPrimeInv = 0;
16
17
18static
19long IsFFTPrime(long n, long& w)
20{
21   long  m, x, y, z;
22   long j, k;
23
24   if (n % 3 == 0) return 0;
25
26   if (n % 5 == 0) return 0;
27
28   if (n % 7 == 0) return 0;
29   
30   m = n - 1;
31   k = 0;
32   while ((m & 1) == 0) {
33      m = m >> 1;
34      k++;
35   }
36
37   for (;;) {
38      x = RandomBnd(n);
39
40      if (x == 0) continue;
41      z = PowerMod(x, m, n);
42      if (z == 1) continue;
43
44      x = z;
45      j = 0;
46      do {
47         y = z;
48         z = MulMod(y, y, n);
49         j++;
50      } while (j != k && z != 1);
51
52      if (z != 1 || y !=  n-1) return 0;
53
54      if (j == k) 
55         break;
56   }
57
58   /* x^{2^k} = 1 mod n, x^{2^{k-1}} = -1 mod n */
59
60   long TrialBound;
61
62   TrialBound = m >> k;
63   if (TrialBound > 0) {
64      if (!ProbPrime(n, 5)) return 0;
65   
66      /* we have to do trial division by special numbers */
67   
68      TrialBound = SqrRoot(TrialBound);
69   
70      long a, b;
71   
72      for (a = 1; a <= TrialBound; a++) {
73         b = (a << k) + 1;
74         if (n % b == 0) return 0; 
75      }
76   }
77
78   /* n is an FFT prime */
79
80   for (j = NTL_FFTMaxRoot; j < k; j++)
81      x = MulMod(x, x, n);
82
83   w = x;
84   return 1;
85}
86
87
88static
89void NextFFTPrime(long& q, long& w)
90{
91   static long m = NTL_FFTMaxRootBnd + 1;
92   static long k = 0;
93
94   long t, cand;
95
96   for (;;) {
97      if (k == 0) {
98         m--;
99         if (m < 5) Error("ran out of FFT primes");
100         k = 1L << (NTL_SP_NBITS-m-2);
101      }
102
103      k--;
104
105      cand = (1L << (NTL_SP_NBITS-1)) + (k << (m+1)) + (1L << m) + 1;
106
107      if (!IsFFTPrime(cand, t)) continue;
108      q = cand;
109      w = t;
110      return;
111   }
112}
113
114
115long CalcMaxRoot(long p)
116{
117   p = p-1;
118   long k = 0;
119   while ((p & 1) == 0) {
120      p = p >> 1;
121      k++;
122   }
123
124   if (k > NTL_FFTMaxRoot)
125      return NTL_FFTMaxRoot;
126   else
127      return k; 
128}
129
130
131void UseFFTPrime(long index)
132{
133   if (index < 0 || index > NumFFTPrimes)
134      Error("invalid FFT prime index");
135
136   if (index < NumFFTPrimes) return;
137
138   long q, w;
139
140   NextFFTPrime(q, w);
141
142   long mr = CalcMaxRoot(q);
143
144   // tables are allocated in increments of 100
145
146   if (index == 0) { 
147      FFTPrime = (long *) NTL_MALLOC(100, sizeof(long), 0);
148      RootTable = (long **) NTL_MALLOC(100, sizeof(long *), 0);
149      RootInvTable = (long **) NTL_MALLOC(100, sizeof(long *), 0);
150      TwoInvTable = (long **) NTL_MALLOC(100, sizeof(long *), 0);
151      FFTPrimeInv = (double *) NTL_MALLOC(100, sizeof(double), 0);
152   }
153   else if ((index % 100) == 0) {
154      FFTPrime = (long *) NTL_REALLOC(FFTPrime, index+100, sizeof(long), 0);
155      RootTable = (long **) 
156                  NTL_REALLOC(RootTable, index+100, sizeof(long *), 0);
157      RootInvTable = (long **) 
158                     NTL_REALLOC(RootInvTable, index+100, sizeof(long *), 0);
159      TwoInvTable = (long **) 
160                    NTL_REALLOC(TwoInvTable, index+100, sizeof(long *), 0);
161      FFTPrimeInv = (double *) 
162                    NTL_REALLOC(FFTPrimeInv, index+100, sizeof(double), 0);
163   }
164
165   if (!FFTPrime || !RootTable || !RootInvTable || !TwoInvTable ||
166       !FFTPrimeInv) 
167      Error("out of space");
168
169   FFTPrime[index] = q;
170
171   long *rt, *rit, *tit;
172
173   if (!(rt = RootTable[index] = (long*) NTL_MALLOC(mr+1, sizeof(long), 0)))
174      Error("out of space");
175   if (!(rit = RootInvTable[index] = (long*) NTL_MALLOC(mr+1, sizeof(long), 0)))
176      Error("out of space");
177   if (!(tit = TwoInvTable[index] = (long*) NTL_MALLOC(mr+1, sizeof(long), 0)))
178      Error("out of space");
179
180   long j;
181   long t;
182
183   rt[mr] = w;
184   for (j = mr-1; j >= 0; j--)
185      rt[j] = MulMod(rt[j+1], rt[j+1], q);
186
187   rit[mr] = InvMod(w, q);
188   for (j = mr-1; j >= 0; j--)
189      rit[j] = MulMod(rit[j+1], rit[j+1], q);
190
191   t = InvMod(2, q);
192   tit[0] = 1;
193   for (j = 1; j <= mr; j++)
194      tit[j] = MulMod(tit[j-1], t, q);
195
196   FFTPrimeInv[index] = 1/double(q);
197
198   NumFFTPrimes++;
199}
200   
201
202static
203long RevInc(long a, long k)
204{
205   long j, m;
206
207   j = k; 
208   m = 1L << (k-1);
209
210   while (j && (m & a)) {
211      a ^= m;
212      m >>= 1;
213      j--;
214   }
215   if (j) a ^= m;
216   return a;
217}
218
219static
220void BitReverseCopy(long *A, const long *a, long k)
221{
222   static long* mem[NTL_FFTMaxRoot+1];
223
224   long n = 1L << k;
225   long* rev;
226   long i, j;
227
228   rev = mem[k];
229   if (!rev) {
230      rev = mem[k] = (long *) NTL_MALLOC(n, sizeof(long), 0);
231      if (!rev) Error("out of memory in BitReverseCopy");
232      for (i = 0, j = 0; i < n; i++, j = RevInc(j, k))
233         rev[i] = j;
234   }
235
236   for (i = 0; i < n; i++)
237      A[rev[i]] = a[i];
238}
239
240
241#ifdef NTL_FFT_PIPELINE
242
243/*****************************************************
244
245   This version of the FFT is written with an explicit
246   "software pipeline", which sometimes speeds things up.
247
248*******************************************************/
249
250void FFT(long* A, const long* a, long k, long q, const long* root)
251
252// performs a 2^k-point convolution modulo q
253
254{
255   if (k == 0) {
256      A[0] = a[0];
257      return;
258   }
259
260   if (k == 1) {
261      A[0] = AddMod(a[0], a[1], q);
262      A[1] = SubMod(a[0], a[1], q);
263      return;
264   }
265
266   // assume k > 1
267
268   long n = 1L << k;
269   long s, m, m2, j;
270   long t, u, v, w, z, tt;
271   long *p1, *p, *ub, *ub1;
272   double qinv = ((double) 1)/((double) q);
273   double wqinv, zqinv;
274
275   BitReverseCopy(A, a, k);
276
277   ub = A+n;
278
279   p = A;
280   while (p < ub) {
281      u = *p;
282      v = *(p+1);
283      *p = AddMod(u, v, q);
284      *(p+1) = SubMod(u, v, q);
285      p += 2;
286   }
287
288   for (s = 2; s < k; s++) {
289      m = 1L << s;
290      m2 = m >> 1;
291
292      p = A;
293      while (p < ub) {
294         u = *p;
295         v = *(p+m2);
296         *p = AddMod(u, v, q);
297         *(p+m2) = SubMod(u, v, q);
298         p += m;
299      }
300
301      z = root[s];
302      w = z;
303      for (j = 1; j < m2; j++) {
304         wqinv = ((double) w)*qinv;
305         p = A + j;
306         p1 = p + m2;
307
308         ub1 = ub-m;
309
310         u = *p;
311         t = MulMod2(*p1, w, q, wqinv);
312
313         while (p < ub1) {
314            tt = MulMod2(*(p1+m), w, q, wqinv);
315            *p = AddMod(u, t, q);
316            *p1 = SubMod(u, t, q);
317            p1 += m;
318            p += m;
319            u = *p;
320            t = tt;
321         }
322         *p = AddMod(u, t, q);
323         *p1 = SubMod(u, t, q);
324         
325         w = MulMod2(z, w, q, wqinv);
326      }
327   }
328
329   m2 = n >> 1;
330   z = root[k];
331   zqinv = ((double) z)*qinv;
332   w = 1;
333   p = A;
334   p1 = A + m2;
335   m2--;
336   u = *p;
337   t = *p1;
338   while (m2) {
339      w = MulMod2(w, z, q, zqinv);
340      tt = MulMod(*(p1+1), w, q, qinv);
341      *p = AddMod(u, t, q);
342      *p1 = SubMod(u, t, q);
343      p++;
344      p1++;
345      u = *p;
346      t = tt;
347      m2--;
348   }
349   *p = AddMod(u, t, q);
350   *p1 = SubMod(u, t, q);
351}
352
353
354
355#else
356
357
358/*****************************************************
359
360   This version of the FFT has no "software pipeline".
361
362******************************************************/
363
364
365
366void FFT(long* A, const long* a, long k, long q, const long* root)
367
368// performs a 2^k-point convolution modulo q
369
370{
371   if (k == 0) {
372      A[0] = a[0];
373      return;
374   }
375
376   if (k == 1) {
377      A[0] = AddMod(a[0], a[1], q);
378      A[1] = SubMod(a[0], a[1], q);
379      return;
380   }
381
382   // assume k > 1
383
384   long n = 1L << k;
385   long s, m, m2, j;
386   long t, u, v, w, z;
387   long *p, *ub, *p1, *ub1;
388   double qinv = ((double) 1)/((double) q);
389   double wqinv, zqinv;
390
391   BitReverseCopy(A, a, k);
392
393   ub = A+n;
394
395   p = A;
396   while (p < ub) {
397      u = *p;
398      v = *(p+1);
399      *p = AddMod(u, v, q);
400      *(p+1) = SubMod(u, v, q);
401      p += 2;
402   }
403
404   for (s = 2; s < k; s++) {
405      m = 1L << s;
406      m2 = m >> 1;
407
408      p = A;
409      while (p < ub) {
410         u = *p;
411         v = *(p+m2);
412         *p = AddMod(u, v, q);
413         *(p+m2) = SubMod(u, v, q);
414         p += m;
415      }
416
417      z = root[s];
418      w = z;
419      for (j = 1; j < m2; j++) {
420         wqinv = ((double) w)*qinv;
421         p = A + j;
422         p1 = p + m2;
423         ub1 = ub-m;
424
425         while (p < ub1) {
426            u = *p;
427            v = *p1;
428            t = MulMod2(v, w, q, wqinv);
429            *p = AddMod(u, t, q);
430            *p1 = SubMod(u, t, q);
431            p += m;
432            p1 += m;
433         }
434
435         u = *p;
436         v = *p1;
437         t = MulMod2(v, w, q, wqinv);
438         *p = AddMod(u, t, q);
439         *p1 = SubMod(u, t, q);
440
441         w = MulMod2(z, w, q, wqinv);
442      }
443   }
444
445   m2 = n >> 1;
446   z = root[k];
447   zqinv = ((double) z)*qinv;
448   w = 1;
449   p = A;
450   for (j = 0; j < m2; j++) {
451      u = *p;
452      v = *(p+m2);
453      t = MulMod(v, w, q, qinv);
454      *p = AddMod(u, t, q);
455      *(p+m2) = SubMod(u, t, q);
456      w = MulMod2(w, z, q, zqinv);
457      p++;
458   }
459}
460
461
462#endif
463
464NTL_END_IMPL
Note: See TracBrowser for help on using the repository browser.