一段写坏掉的快速DCT实现

想当然了,用递归实现DCT,没想到DCT有4个分支需要递归下去,这样的规模非但无法快速实现,反而由于本身时间复杂度没有多大减少加上递归开销等等比慢速实现往往还慢。

这个代码片段将由于清洁需要从QSharp中删除而保留在这里,对其分析将在代码之后有空时进行。过两天想想是不是能用动态规划或备忘录来改进这个算法。

  1 /// <summary>
  2 ///  Type-IV DCT implemented using recursive method
  3 ///  Warning: This method is mathematically crippled even slower than the normal one and thereby not suitable for fast caluculation
  4 /// </summary>
  5 /// <param name="input">The input sequence</param>
  6 /// <param name="output">The output sequence</param>
  7 public static void FctIvRecursive(this IList<double> input, IList<double> output)
  8 {
  9     var n = new DftMethods.FactorAidedInteger(input.Count);
 10     input.FctIvRecursiveCore(n, 0, 1, output);
 11 }
 12 
 13 private static void DctIvFCore(this IList<double> input, int start, int skip, double a, IList<double> output)
 14 {
 15     var ni = input.Count;
 16     var n = output.Count;
 17     for (var k = 0; k < n; k++)
 18     {
 19         var d = 0.0;
 20         var j = 0;
 21         for (var i = start; i < ni; i += skip, j++)
 22         {
 23             var v = input[i] * Math.Cos(a * (k + 0.5) * (j + 0.5));
 24             if (j % 2 != 0)
 25             {
 26                 v = -v;
 27             }
 28             d += v;
 29         }
 30         output[k] = d;
 31     }
 32 }
 33 
 34 private static void DstIvCore(this IList<double> input, int start, int skip, double a, IList<double> output)
 35 {
 36     var ni = input.Count;
 37     var n = output.Count;
 38     for (var k = 0; k < n; k++)
 39     {
 40         var d = 0.0;
 41         var j = 0;
 42         for (var i = start; i < ni; i += skip, j++)
 43         {
 44             d += input[i]*Math.Sin(a*(k + 0.5)*(j + 0.5));
 45         }
 46         output[k] = d;
 47     }
 48 }
 49 
 50 private static void DstIvFCore(this IList<double> input, int start, int skip, double a, IList<double> output)
 51 {
 52     var ni = input.Count;
 53     var n = output.Count;
 54     for (var k = 0; k < n; k++)
 55     {
 56         var d = 0.0;
 57         var j = 0;
 58         for (var i = start; i < ni; i += skip, j++)
 59         {
 60             var v = input[i] * Math.Sin(a * (k + 0.5) * (j + 0.5));
 61             if (j % 2 != 0)
 62             {
 63                 v = -v;
 64             }
 65             d += v;
 66         }
 67         output[k] = d;
 68     }
 69 }
 70 
 71 
 72 private static void FctIvRecursiveCore(this IList<double> input,
 73                                        DftMethods.FactorAidedInteger n, int start, int skip,
 74                                        IList<double> output)
 75 {
 76     var n0 = n.N;
 77     var n1 = n.Decompose();
 78     var n2 = n.N;
 79     var a = Math.PI/n0;
 80 
 81     if (n1 > 1 && n2 > 1)
 82     {
 83         for (var k = 0; k < n0; k++)
 84         {
 85             output[k] = 0;
 86         }
 87 
 88         var b = 0.25*a;
 89         for (var r = 0; r < n1; r++)
 90         {
 91             int newStart, newSkip;
 92 
 93             DftMethods.GetSubsequenceIndexGenerator(start, skip, r, n1, out newStart, out newSkip);
 94 
 95             // N2-point DCT and DST
 96             var tmpDct = new double[n2];
 97             var tmpDst = new double[n2];
 98             var tmpDctF = new double[n2];
 99             var tmpDstF = new double[n2];
100             input.FctIvRecursiveCore(n, newStart, newSkip, tmpDct);
101             input.FstIvRecursiveCore(n, newStart, newSkip, tmpDst);
102             input.FctIvFRecursiveCore(n, newStart, newSkip, tmpDctF);
103             input.FstIvFRecursiveCore(n, newStart, newSkip, tmpDstF);
104 
105             var c = b*(2*r + 1 - n1);
106             for (var k = 0; k < n0; k++)
107             {
108                 var k2 = k%n2;
109                 var l = k/n2;
110                 var phi = c*(2*k + 1);
111                 var lMod4 = l%4;
112                 switch (lMod4)
113                 {
114                     case 0:
115                         output[k] += tmpDct[k2] * Math.Cos(phi) - tmpDst[k2] * Math.Sin(phi);
116                         break;
117                     case 2:
118                         output[k] += -tmpDct[k2] * Math.Cos(phi) + tmpDst[k2] * Math.Sin(phi);
119                         break;
120                     case 1:
121                         output[k] += -tmpDstF[k2] * Math.Cos(phi) - tmpDctF[k2] * Math.Sin(phi);
122                         break;
123                     case 3:
124                         output[k] += tmpDstF[k2] * Math.Cos(phi) + tmpDctF[k2] * Math.Sin(phi);
125                         break;
126                 }
127             }
128         }
129     }
130     else
131     {
132         input.DctIvCore(start, skip, a, output);
133     }
134 
135     n.Restore(n1);
136 }
137 
138 private static void FstIvRecursiveCore(this IList<double> input,
139                                        DftMethods.FactorAidedInteger n, int start, int skip,
140                                        IList<double> output)
141 {
142     var n0 = n.N;
143     var n1 = n.Decompose();
144     var n2 = n.N;
145     var a = Math.PI/n0;
146 
147     if (n1 > 1 && n2 > 1)
148     {
149         for (var k = 0; k < n0; k++)
150         {
151             output[k] = 0;
152         }
153 
154         var b = 0.25*a;
155         for (var r = 0; r < n1; r++)
156         {
157             int newStart, newSkip;
158 
159             DftMethods.GetSubsequenceIndexGenerator(start, skip, r, n1, out newStart, out newSkip);
160 
161             // N2-point DCT and DST
162             var tmpDct = new double[n2];
163             var tmpDst = new double[n2];
164             var tmpDctF = new double[n2];
165             var tmpDstF = new double[n2];
166             input.FctIvRecursiveCore(n, newStart, newSkip, tmpDct);
167             input.FstIvRecursiveCore(n, newStart, newSkip, tmpDst);
168             input.FctIvFRecursiveCore(n, newStart, newSkip, tmpDctF);
169             input.FstIvFRecursiveCore(n, newStart, newSkip, tmpDstF);
170 
171             var c = b*(2*r + 1 - n1);
172             for (var k = 0; k < n0; k++)
173             {
174                 var k2 = k%n2;
175                 var l = k/n2;
176                 var phi = c*(2*k + 1);
177                 var lMod4 = l % 4;
178                 switch (lMod4)
179                 {
180                     case 0:
181                         output[k] += tmpDst[k2] * Math.Cos(phi) + tmpDct[k2] * Math.Sin(phi);
182                         break;
183                     case 2:
184                         output[k] += -tmpDst[k2] * Math.Cos(phi) - tmpDct[k2] * Math.Sin(phi);
185                         break;
186                     case 1:
187                         output[k] += tmpDctF[k2] * Math.Cos(phi) - tmpDstF[k2] * Math.Sin(phi);
188                         break;
189                     case 3:
190                         output[k] += -tmpDctF[k2] * Math.Cos(phi) + tmpDstF[k2] * Math.Sin(phi);
191                         break;
192                 }
193             }
194         }
195     }
196     else
197     {
198         input.DstIvCore(start, skip, a, output);
199     }
200 
201     n.Restore(n1);
202 }
203 
204 private static void FctIvFRecursiveCore(this IList<double> input,
205                                         DftMethods.FactorAidedInteger n, int start, int skip,
206                                         IList<double> output)
207 {
208     var n0 = n.N;
209     var n1 = n.Decompose();
210     var n2 = n.N;
211     var a = Math.PI / n0;
212 
213     if (n1 > 1 && n2 > 1)
214     {
215         for (var k = 0; k < n0; k++)
216         {
217             output[k] = 0;
218         }
219 
220         var b = 0.25 * a;
221         for (var r = 0; r < n1; r++)
222         {
223             int newStart, newSkip;
224 
225             DftMethods.GetSubsequenceIndexGenerator(start, skip, r, n1, out newStart, out newSkip);
226 
227             // N2-point DCT and DST
228             var tmpDct1 = new double[n2];
229             var tmpDst1 = new double[n2];
230             var tmpDct2 = new double[n2];
231             var tmpDst2 = new double[n2];
232             if (n1%2 == 0)
233             {
234                 input.FctIvRecursiveCore(n, newStart, newSkip, tmpDct1);
235                 input.FstIvRecursiveCore(n, newStart, newSkip, tmpDst1);
236                 input.FctIvFRecursiveCore(n, newStart, newSkip, tmpDct2);
237                 input.FstIvFRecursiveCore(n, newStart, newSkip, tmpDst2);
238             }
239             else
240             {
241                 input.FctIvRecursiveCore(n, newStart, newSkip, tmpDct2);
242                 input.FstIvRecursiveCore(n, newStart, newSkip, tmpDst2);
243                 input.FctIvFRecursiveCore(n, newStart, newSkip, tmpDct1);
244                 input.FstIvFRecursiveCore(n, newStart, newSkip, tmpDst1);
245             }
246 
247             var c = b*(2*r + 1 - n1);
248             var rIsOdd = r%2 != 0;
249             for (var k = 0; k < n0; k++)
250             {
251                 var k2 = k % n2;
252                 var l = k / n2;
253                 var phi = c * (2 * k + 1);
254                 var lMod4 = l % 4;
255                 var d = 0.0;
256                 switch (lMod4)
257                 {
258                     case 0:
259                         d = tmpDct1[k2] * Math.Cos(phi) - tmpDst1[k2] * Math.Sin(phi);
260                         break;
261                     case 2:
262                         d = -tmpDct1[k2] * Math.Cos(phi) + tmpDst1[k2] * Math.Sin(phi);
263                         break;
264                     case 1:
265                         d = -tmpDst2[k2] * Math.Cos(phi) - tmpDct2[k2] * Math.Sin(phi);
266                         break;
267                     case 3:
268                         d = tmpDst2[k2] * Math.Cos(phi) + tmpDct2[k2] * Math.Sin(phi);
269                         break;
270                 }
271                 if (rIsOdd)
272                 {
273                     d = -d;
274                 }
275                 output[k] += d;
276             }
277         }
278     }
279     else
280     {
281         input.DctIvFCore(start, skip, a, output);
282     }
283 
284     n.Restore(n1);
285 }
286 
287 private static void FstIvFRecursiveCore(this IList<double> input,
288                                         DftMethods.FactorAidedInteger n, int start, int skip,
289                                         IList<double> output)
290 {
291     var n0 = n.N;
292     var n1 = n.Decompose();
293     var n2 = n.N;
294     var a = Math.PI / n0;
295 
296     if (n1 > 1 && n2 > 1)
297     {
298         for (var k = 0; k < n0; k++)
299         {
300             output[k] = 0;
301         }
302 
303         var b = 0.25 * a;
304         for (var r = 0; r < n1; r++)
305         {
306             int newStart, newSkip;
307 
308             DftMethods.GetSubsequenceIndexGenerator(start, skip, r, n1, out newStart, out newSkip);
309 
310             // N2-point DCT and DST
311             var tmpDct1 = new double[n2];
312             var tmpDst1 = new double[n2];
313             var tmpDct2 = new double[n2];
314             var tmpDst2 = new double[n2];
315             if (n1%2 == 0)
316             {
317                 input.FctIvRecursiveCore(n, newStart, newSkip, tmpDct1);
318                 input.FstIvRecursiveCore(n, newStart, newSkip, tmpDst1);
319                 input.FctIvFRecursiveCore(n, newStart, newSkip, tmpDct2);
320                 input.FstIvFRecursiveCore(n, newStart, newSkip, tmpDst2);
321             }
322             else
323             {
324                 input.FctIvRecursiveCore(n, newStart, newSkip, tmpDct2);
325                 input.FstIvRecursiveCore(n, newStart, newSkip, tmpDst2);
326                 input.FctIvFRecursiveCore(n, newStart, newSkip, tmpDct1);
327                 input.FstIvFRecursiveCore(n, newStart, newSkip, tmpDst1);
328             }
329 
330             var c = b * (2 * r + 1 - n1);
331             var rIsOdd = r%2 != 0;
332             for (var k = 0; k < n0; k++)
333             {
334                 var k2 = k % n2;
335                 var l = k / n2;
336                 var phi = c * (2 * k + 1);
337                 var lMod4 = l % 4;
338                 var d = 0.0;
339                 switch (lMod4)
340                 {
341                     case 0:
342                         d = tmpDst1[k2] * Math.Cos(phi) + tmpDct1[k2] * Math.Sin(phi);
343                         break;
344                     case 2:
345                         d = -tmpDst1[k2] * Math.Cos(phi) - tmpDct1[k2] * Math.Sin(phi);
346                         break;
347                     case 1:
348                         d = tmpDct2[k2] * Math.Cos(phi) - tmpDst2[k2] * Math.Sin(phi);
349                         break;
350                     case 3:
351                         d = tmpDct2[k2] * Math.Cos(phi) - tmpDst2[k2] * Math.Sin(phi);
352                         break;
353                 }
354                 if (rIsOdd)
355                 {
356                     d = -d;
357                 }
358                 output[k] += d;
359             }
360         }
361     }
362     else
363     {
364         input.DstIvFCore(start, skip, a, output);
365     }
366 
367     n.Restore(n1);
368 }

 

posted @ 2013-03-26 00:36  quanben  阅读(286)  评论(0编辑  收藏  举报