一段写坏掉的快速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 }
enjoy every minute of an appless, googless and oracless life