user-0 提问: 有快速从数组中提取所有偶数项的算法吗？

回复:
user: user-0
content: 粗略讲一下测试结果。 我最初的代码： for(i=0; i<640*480; i++) {     if(i % 2 == 0)      {         b[j] = a[i];         j++;     } }循环次数多，还多了次取模，计算时间较长。计算一次用了25ms。  －－－－－－－－－－－－－－－ 3楼的lm_whales兄弟帮我缩减了循环次数和取模，一次用时缩减到16ms。 for(i=0; i<640*480; i+=2,j++) {           b[j] = a[i]; } 至于移位和*2， 计算速度是大致相同的。  －－－－－－－－－－－－－－－－－－－－－－ 15楼的chehw_1兄弟把char改成u32方式后，循环次数进一步减少了，一次用时10ms。#define GET_EVEN_BYTES(x1, x2)  (x1 & 0xff) | (((x1 >> 16) & 0xff) << 8) | \                                 (((x2 & 0xff)) << 16) | (((x2 >> 16) & 0xff) << 24)      static void func1(const char * a, size_t size, char * b) {     uint32_t * p_a = (uint32_t *)a;     uint32_t * p_end = (uint32_t *)(a + size);     uint32_t * p_b = (uint32_t *)b;           while(p_a < p_end)     {         *p_b++ = (uint32_t)GET_EVEN_BYTES(p_a[0], p_a[1]);         p_a += 2;            } }  －－－－－－－－－－－－－－－－－－－－ 至于汇编算法，目前代码还没有调通，寄存器的定义不知道如何加入。日后再进行研究。  再次谢谢回复的各位。

user: user-0
content: 这几天比较忙，都还没来得及试试各位大虾的代码。有点辜负大家了。一定安排时间逐一测试给出结论。 赵老师给的汇编代码，经过上网查资料后，终于看懂了。一定试试。 先结贴了，感谢各位大虾如此地支持我，真的受益匪浅。 欢迎各位继续接着讨论或吐槽。 立贴时出分数太少，给分少了各位别见怪。

user: user-1
content: 引用 31 楼 DelphiGuy 的回复:楼主说的是“源数据数组， 如 char a[640 * 480]”，大嘴你非要整成int/short... 最近我好象眼睛里面揉进沙子了。 #include <stdio.h> char a[640*480]; char b[640*480/2]; void func1() {     int i;     int j = 0;     for (i=0; i<640*480; i++) {         if (i % 2 == 0) {             b[j] = a[i];             j++;         }     } } void func2() {     __asm {         push esi         push edi         push ecx         lea esi,a         lea edi,b         mov ecx,640*480/2         cld     step1:         lodsb         stosb         inc esi         loop step1         pop ecx         pop edi         pop esi     } } int main() {     for (int i=0; i<640*480; i++) a[i]=(char)(i%100);     func1();     printf("%d\n",b[640*480/2-1]);     b[640*480/2-1]=0;     func2();     printf("%d\n",b[640*480/2-1]);     return 0; } //98 //98 //

user: user-1
content: 引用 30 楼 DelphiGuy 的回复:[quote=引用 27 楼 zhao4zhong1 的回复:] [quote=引用 24 楼 DelphiGuy 的回复:] 赵家这繁衍速度够快的，平均2.2年一代。 我说1024是十进制了吗？[/quote]  不愧是赵中赵大嘴。 没有特殊标记，默认就是十进制。即便是五进制，139代也快了一些，四进制还可以。 [/quote] 完了，惹上一个专挑我错的。关键还每次都挑得对。 看来我廉颇老矣！

user: user-2
content: 楼主说的是“源数据数组， 如 char a[640 * 480]”，大嘴你非要整成int/short...

user: user-2
content: 引用 27 楼 zhao4zhong1 的回复:[quote=引用 24 楼 DelphiGuy 的回复:] 赵家这繁衍速度够快的，平均2.2年一代。 我说1024是十进制了吗？[/quote]  不愧是赵中赵大嘴。 没有特殊标记，默认就是十进制。即便是五进制，139代也快了一些，四进制还可以。

user: user-3
content: 具体思路就是汇编层面循环多少次，有几个汇编指令。 Profiler在比较不同版本下差异使用。 但是CPU操作本身就比较耗时，如果使用DSP或者FPGA才是大块内存复制的不二选择！

user: user-0
content: 引用 28 楼 zhao4zhong1 的回复:unsigned short int版： #include <stdio.h> unsigned short int a[640*480]; unsigned short int b[640*480/2]; void func1() {     int i;     int j = 0;     for (i=0; i<640*480; i++) {         if (i % 2 == 0) {             b[j] = a[i];             j++;         }     } } void sfunc2() {     __asm {         push esi         push edi         push ecx         lea esi,a         lea edi,b         mov ecx,640*480/2         cld     step1:         lodsw         stosw         add esi,2         loop step1         pop ecx         pop edi         pop esi     } } int main() {     for (int i=0; i<640*480; i++) a[i]=(unsigned short int)(i%65536);     func1();     printf("%hu\n",b[640*480/2-1]);     b[640*480/2-1]=0;     sfunc2();     printf("%hu\n",b[640*480/2-1]);     return 0; } //45054 //45054 //  汇编寄存器还得再熟悉熟悉才能看懂这代码。

user: user-4
content: 既然是复制，就没有多少捷径可走。在寄存器上操作要比访问内存快得多。因此，如果你的寄存器宽度是64比特，则你可以一次性读取8个字节（假定一个字节是8个比特），然后挑取偶数单元，交换重排再写入。 其实这个问题还得视处理器的类型而定，如果处理器提供了现成的指令，则方便得多，也快得多。比如，x86处理器提供了REP MOVSD和BSWAP指令。

user: user-2
content: 赵家这繁衍速度够快的，平均2.2年一代。

user: user-1
content: Linux下的profiler我没用过。 其实就连VS2005的profiler我也没用过！ 不过好在我还是用过VC6的profiler的。 不然我岂不成了纸上谈兵的赵括的第1024代孙？

user: user-0
content: 引用 21 楼 zhao4zhong1 的回复:18楼忘附图了。 无profiler不要谈效率！！尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代！ 赵老师能推荐个在Linux下使用的profiler吗？昨天在赵老师提点后，查了一下，GNU用的profiler工具还是挺多的，不知道哪个好。

user: user-0
content: 引用 25 楼 user-5 的回复:嵌入式的话可以看看芯片提供的接口，这种取值使用dma是最快的，现在很多图像处理的dsp都提供了这样的dma操作。 数据拿到了，是作分析时的操作。

user: user-1
content: unsigned short int版： #include <stdio.h> unsigned short int a[640*480]; unsigned short int b[640*480/2]; void func1() {     int i;     int j = 0;     for (i=0; i<640*480; i++) {         if (i % 2 == 0) {             b[j] = a[i];             j++;         }     } } void sfunc2() {     __asm {         push esi         push edi         push ecx         lea esi,a         lea edi,b         mov ecx,640*480/2         cld     step1:         lodsw         stosw         add esi,2         loop step1         pop ecx         pop edi         pop esi     } } int main() {     for (int i=0; i<640*480; i++) a[i]=(unsigned short int)(i%65536);     func1();     printf("%hu\n",b[640*480/2-1]);     b[640*480/2-1]=0;     sfunc2();     printf("%hu\n",b[640*480/2-1]);     return 0; } //45054 //45054 //

user: user-1
content: 引用 24 楼 DelphiGuy 的回复:赵家这繁衍速度够快的，平均2.2年一代。 我说1024是十进制了吗？

user: user-1
content: 引用 12 楼 chenben 的回复:[quote=引用 8 楼 jennyvenus 的回复:] 如芯片上没有特殊功能，没什么办法了，各种写法，对于一个优秀的编译器来讲，最终代码差不多，  可以将源数组看成short数组，目的数组还是byte， byte[ i ] = short[ i ];让编译器自己做事  或者可以考虑汇编。  我的主芯片不是dsp，不是fpga。 把数据源看车short型的想法不错，我试试看。谢谢。 我不懂汇编，但应该可以插入汇编代码。有没有哪位汇编高手指教一下。[/quote] #include <stdio.h> int a[640*480]; int b[640*480/2]; void func1() {     int i;     int j = 0;     for (i=0; i<640*480; i++) {         if (i % 2 == 0) {             b[j] = a[i];             j++;         }     } } void func2() {     __asm {         push esi         push edi         push ecx         lea esi,a         lea edi,b         mov ecx,640*480/2         cld     step1:         lodsd         stosd         add esi,4         loop step1         pop ecx         pop edi         pop esi     } } int main() {     for (int i=0; i<640*480; i++) a[i]=i;     func1();     printf("%d\n",b[640*480/2-1]);     b[640*480/2-1]=0;     func2();     printf("%d\n",b[640*480/2-1]);     return 0; } //307198 //307198 //

user: user-5
content: 嵌入式的话可以看看芯片提供的接口，这种取值使用dma是最快的，现在很多图像处理的dsp都提供了这样的dma操作。

user: user-1
content: 18楼忘附图了。 无profiler不要谈效率！！尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代！

user: user-0
content: 引用 18 楼 zhao4zhong1 的回复:无profiler不要谈效率！！尤其在这个云计算、虚拟机、模拟器、CUDA、多核 、多级cache、指令流水线、多种存储介质、……满天飞的时代！ 感谢赵老师总给我们提供方向。

user: user-0
content: 引用 15 楼 chehw_1 的回复:func1是用手工优化的方式来实现，将位运算的结果赋值给uint类型，这通常比直接逐字节赋值要快很多。 func2是用最简单易懂的方式来实现。 如果不通过编译器优化： $ gcc -o test1 test1.c $ ./test1 func1 time: 1.317621 func2 time: 4.110902  -O2 优化下： $ gcc -O2 -o test1 test1.c $ ./test1 func1 time: 0.688920 func2 time: 1.076817  此时，手工优化的代码（func1)均比简洁方式的代码（func2)快很多；但是，  -O6优化下，简洁方式的代码效率胜出了： $ gcc -O6 -o test1 test1.c $ ./test1 func1 time: 0.255404 func2 time: 0.207539 很感谢。我在看是不是因为这种方法减少了循环的使用，所以省了时间。让我想想怎么验证这种想法。