2010-08-02 30 views
13

我通常可以找出大多數的C代碼,但這一個是在我的頭上。有人可以幫忙解釋一下C這個班輪是幹什麼的嗎?

#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) 

示例用法會是這樣的:

int x = 57; 
kroundup32(x); 
//x is now 64 

其他一些實例是:

1至1
2至2
7-8
31至32
60至64
3000至4096

我知道它是四捨五入的整數,它是2的最近冪,但就我的知識而言就是這樣。

任何解釋將不勝感激。

由於

回答

20
(--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x)) 
  1. 減少x除以1
  2. OR x,其中(X/2)。
  3. 或x與(x/4)。
  4. 或x與(x/16)。
  5. 或x與(x/256)。
  6. 或x與(x/65536)。通過1

對於32位無符號整數

  • 增加量X,這應該移動的值達到2的最接近功率等於或更大。 OR部分設置低於最高位的所有低位,因此它以2的冪減1的方式結束,然後向其中添加一個。它看起來有點優化,因此不太可讀;通過按位操作和單獨位移來完成,並作爲一個宏(所以沒有函數調用開銷)。

  • +0

    太好了,我明白現在在做什麼。謝謝! – GWW 2010-08-02 03:50:57

    +0

    對於編碼(優化)+1的人+1對@thomasrutter進行解碼:) – KedarX 2010-08-02 06:07:36

    +0

    恩,這不是真的只適用於16位嗎? – 2010-08-02 07:50:27

    6

    按位或移位操作基本上設置最高設置位和零位之間的每個位。這會產生一些表格2^n - 1。最後一個增量會添加一個以獲得2^n的數字。初始遞減確保你不會將已經是2的冪次數的數整理到下一次冪,因此例如2048不會成爲4096

    6

    在我的機器kroundup32給6.000米發/秒
    而旁邊函數給出7.693米發/秒

    inline int scan_msb(int x) 
    { 
    #if defined(__i386__) || defined(__x86_64__) 
        int y; 
        __asm__("bsr %1, %0" 
          : "=r" (y) 
          : "r" (x) 
          : "flags"); /* ZF */ 
        return y; 
    #else 
    #error "Implement me for your platform" 
    #endif 
    } 
    
    inline int roundup32(int x) 
    { 
        if (x == 0) return x; 
        else { 
         const int bit = scan_msb(x); 
         const int mask = ~((~0) << bit); 
         if (x & mask) return (1 << (bit+1)); 
         else return (1 << bit); 
        } 
    } 
    

    所以@thomasrutter我woudn't說,這是「高度優化」。

    和適當的(唯一有意義的部分)組件(對於GCC 4.4.4):

    kroundup32: 
        subl $1, %edi 
        movl %edi, %eax 
        sarl %eax 
        orl %edi, %eax 
        movl %eax, %edx 
        sarl $2, %edx 
        orl %eax, %edx 
        movl %edx, %eax 
        sarl $4, %eax 
        orl %edx, %eax 
        movl %eax, %edx 
        sarl $8, %edx 
        orl %eax, %edx 
        movl %edx, %eax 
        sarl $16, %eax 
        orl %edx, %eax 
        addl $1, %eax 
        ret 
    
    roundup32: 
        testl %edi, %edi 
        movl %edi, %eax 
        je .L6 
        movl $-1, %edx 
        bsr %edi, %ecx 
        sall %cl, %edx 
        notl %edx 
        testl %edi, %edx 
        jne .L10 
        movl $1, %eax 
        sall %cl, %eax 
    .L6: 
        rep 
        ret 
    .L10: 
        addl $1, %ecx 
        movl $1, %eax 
        sall %cl, %eax 
        ret 
    

    由於某種原因我沒有GCC的非標準頭中發現的scan_msb(如#define scan_msb(x) if (__builtin_constant_p (x)) ...)適當的實現(只__TBB_machine_lg/__TBB_Log2)。

    +1

    夠公平的。我想你可以說,無論誰寫這封信都試圖*做出高度優化的事情,即使這種嘗試可能不會很成功;) – thomasrutter 2010-08-05 05:26:50

    相關問題