找回密码
 欢迎注册
楼主: gxqcn

[讨论] 一个快速得到bit位索引的算法

[复制链接]
发表于 2008-3-10 10:07:43 | 显示全部楼层
附详细代码
并请终止任何当前占CPU程序

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

DWORD bits[32];

void find(DWORD a, DWORD * b, DWORD *c)
{
        __asm
        {
      mov   eax, dword ptr [a]      
      xor   esi, esi   
    loop1:      
      bsr   edi, eax
      je exit1
      xor   eax, dword ptr [bits + 4 * edi]
      mov   dword  ptr [b + 4*esi], edi            
      inc   esi   
      jmp   loop1
    exit1:      
      mov   dword ptr [c], esi
        }
}

DWORD find_by_GxQ(DWORD code, DWORD index[33])
{
    __asm
    {
        mov     ecx, code;

        xor     eax, eax;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 0;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 1;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 2;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 3;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 4;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 5;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 6;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 7;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 8;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 9;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 10;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 11;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 12;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 13;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 14;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 15;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 16;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 17;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 18;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 19;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 20;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 21;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 22;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 23;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 24;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 25;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 26;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 27;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 28;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 29;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 30;
        adc     eax, 0;

        shr     ecx, 1;
        mov     dword ptr[index + 4*eax], 31;
        adc     eax, 0;

        // 休止符
        mov     dword ptr[index + 4*eax], -1;
    }
}

int   main(int   argc,   char *   argv[])
{
::SetThreadPriority(::GetCurrentThread(),   THREAD_PRIORITY_TIME_CRITICAL);
LARGE_INTEGER   lTimestart,   lTimeEnd,   liFreq;

DWORD c, bitMask = 1, index[33];

for (DWORD i = 0; i < 31; i ++)
{
  bits[i] = bitMask;
  bitMask <<= 1;
}

QueryPerformanceCounter(&lTimestart);
for(DWORD   i   =   0;   i   <   1000000;   i++){
  find(i,  &index[0], &c);//   调用bit扫描函数
}
QueryPerformanceCounter(&lTimeEnd);
QueryPerformanceFrequency(&liFreq);

double   dbMs   =   ((double)   (lTimeEnd.QuadPart   -   lTimestart.QuadPart)   *   1000)   /   (double)liFreq.QuadPart;
printf("yaos: %.3f\n", dbMs);

QueryPerformanceCounter(&lTimestart);
for(DWORD   i   =   0;   i   <   1000000;   i++){
  find_by_GxQ(i,  index);//   调用bit扫描函数
}
QueryPerformanceCounter(&lTimeEnd);
QueryPerformanceFrequency(&liFreq);

dbMs   =   ((double)   (lTimeEnd.QuadPart   -   lTimestart.QuadPart)   *   1000)   /   (double)liFreq.QuadPart;
printf("GXQ: %.3f\n", dbMs);

system("Pause");

return   0;
}
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-10 10:10:12 | 显示全部楼层
测试机器P4 XEON 2.0 X 2, 1G DDR 多次比较时间 E:\yaojialin\FindBits\Debug>findbits yaos: 154.030 GXQ: 174.165 请按任意键继续. . . E:\yaojialin\FindBits\Debug>findbits yaos: 153.931 GXQ: 174.422 请按任意键继续. . . E:\yaojialin\FindBits\Debug>findbits yaos: 153.751 GXQ: 171.132 请按任意键继续. . . E:\yaojialin\FindBits\Debug>findbits yaos: 154.908 GXQ: 171.753 请按任意键继续. . . E:\yaojialin\FindBits\Debug>findbits yaos: 156.030 GXQ: 171.409 请按任意键继续. . . E:\yaojialin\FindBits\Debug>findbits yaos: 154.036 GXQ: 171.994 请按任意键继续. . . E:\yaojialin\FindBits\Debug>findbits yaos: 154.855 GXQ: 173.272 请按任意键继续. . .
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-10 10:38:18 | 显示全部楼层
原帖由 无心人 于 2008-3-10 10:07 发表 ... for(DWORD i = 0; i < 1000000; i++){ find(i, &index[0], &c);// 调用bit扫描函数 } ...
这个测试是不科学的,因为被测数(i)的高12位永远为0,若用判断语句可提前退出, 所以对被测函数不公平。比较好的是用随机数(我原来测试是$2^24=16777216$个随机数) 另外,你的函数在我的机器上无法运行。看了一下你的汇编,错误比较多: void find(DWORD a, DWORD * b, DWORD *c) { __asm { mov eax, dword ptr [a] xor esi, esi loop1: bsr edi, eax je exit1 xor eax, dword ptr [bits + 4 * edi] mov dword ptr [b + 4*esi], edi inc esi jmp loop1 exit1: mov dword ptr [c], esi } } 其中:bsr按你的思路应为bsf, 另外,请自己debug一下,b,c是否成功?(需要将它们地址存到寄存器中才可访问内容)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-10 10:49:15 | 显示全部楼层
原帖由 无心人 于 2008-3-10 10:06 发表 总感觉不对劲 终于觉醒了 似乎我是测试的1000万, 你们测试的是100万 把GXQ代码和我代码聚集在一起 终于比较出来了 还是我的快 我冤啊
你看错了,我们测试的是 0x1000000 = 16777216 个随机数,比你的更大更好。 在公司里我无法下载论坛附件,但从你给出的代码感觉非常不合理。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-10 11:22:58 | 显示全部楼层
那你测试下 我是根据100万做的
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-10 11:36:48 | 显示全部楼层
咱测全32位数字如何??? 0 - FFFFFFFF 我就想看看位操作和技巧到底谁好 =========================== 另外你说的不对 位扫描不管数字如何 总执行周期就是32 0也要一位位扫描下去 不过是CPU代替循环而已
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-10 11:39:13 | 显示全部楼层
你的汇编犯有低级错误,我已在 23# 中给你指出来了。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-10 11:54:50 | 显示全部楼层
能通过编译啊 老大
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-10 12:54:28 | 显示全部楼层
编译过,但运行结果错,那就毫无意义了。 算了,好事做到底,把你的代码修正过来了,请你自测吧(在我这儿你的远远落后):
  1. DWORD bits[32];
  2. void find(DWORD a, DWORD * b, DWORD *c)
  3. {
  4. __asm
  5. {
  6. mov eax, a;
  7. mov edx, dword ptr b;
  8. xor esi, esi;
  9. loop1:
  10. bsf edi, eax;
  11. je exit1;
  12. xor eax, dword ptr [bits + 4 * edi];
  13. mov dword ptr [edx + 4*esi], edi;
  14. inc esi;
  15. jmp loop1;
  16. exit1:
  17. mov edx, dword ptr c;
  18. mov dword ptr [edx], esi;
  19. }
  20. }
复制代码
调整一下寄存器名,代码如下:
  1. DWORD bits[32];
  2. void find(DWORD a, DWORD * b, DWORD *c)
  3. {
  4. __asm
  5. {
  6. mov edx, a;
  7. mov edi, dword ptr b;
  8. xor eax, eax;
  9. loop1:
  10. bsf ecx, edx;
  11. je exit1;
  12. xor edx, dword ptr [bits + 4 * ecx];
  13. mov dword ptr [edi + 4*eax], ecx;
  14. add eax, 1;
  15. jmp loop1;
  16. exit1:
  17. mov edi, dword ptr c;
  18. mov dword ptr [edi], eax;
  19. }
  20. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-10 13:35:07 | 显示全部楼层
老大啊 bsr乃反向位扫描啊 我发这的意思 基于下面的疑惑 你们汇编远大于我的代码的4倍 假使你们以每周期4个指令执行 也不能远大于我的时间 我代码应该没明显的阻塞地方 并不是说谁的代码不好 我弄不明白我不死心 ========================== 我这里我的162 你的171 按你改的代码, 比我自己的慢4ms
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-22 01:01 , Processed in 0.034905 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表