簡體   English   中英

高階位 - 取出它們並將uint64_t轉換為uint8_t

[英]High Order Bits - Take them and make a uint64_t into a uint8_t

假設您有一個uint64_t,並且只關心uint64_t中每個字節的高位。 像這樣:

uint32_t:0000 ... 1000 0000 1000 0000 1000 0000 1000 0000 ---> 0000 1111

有沒有比以下更快的方式:

   return
   (
     ((x >> 56) & 128)+
     ((x >> 49) &  64)+
     ((x >> 42) &  32)+
     ((x >> 35) &  16)+
     ((x >> 28) &   8)+
     ((x >> 21) &   4)+
     ((x >> 14) &   2)+
     ((x >>  7) &   1)
   )

Aka移位x,屏蔽並為每個字節添加正確的位? 這將編譯到很多程序集,我正在尋找一個更快的方法...我使用的機器只有SSE2指令,我找不到有用的SIMD操作。

謝謝您的幫助。

正如我在評論中提到的, pmovmskb做你想要的。 以下是您可以使用它的方法:

MMX + SSE1:

movq mm0, input ; input can be r/m
pmovmskb output, mm0 ; output must be r

SSE2:

movq xmm0, input
pmovmskb output, xmm0

我抬頭看着新的方式

BMI2:

mov rax, 0x8080808080808080
pext output, input, rax ; input must be r
return ((x & 0x8080808080808080) * 0x2040810204081) >> 56;

作品。 &選擇要保留的位。 將所有位乘以最高有效字節,並將移位移到最低有效字節。 由於在大多數現代CPU上乘法很快,因此這不應該比使用匯編慢得多。

以下是使用SSE內在函數的方法:

#include <xmmintrin.h>
#include <inttypes.h>
#include <stdio.h>

int main (void)
{
  uint64_t x
  = 0b0000000010000000000000001000000000000000100000000000000010000000;

  printf ("%x\n", _mm_movemask_pi8 ((__m64) x));
  return 0;
}

適用於:

gcc -msse

您不需要所有單獨的邏輯AND,您可以將其簡化為:

x &= 0x8080808080808080;
return (x >>  7) | (x >> 14) | (x >> 21) | (x >> 28) |
       (x >> 35) | (x >> 42) | (x >> 49) | (x >> 56);

(假設函數返回類型是uint8_t )。

您還可以將其轉換為展開循環:

uint8_t r = 0;

x &= 0x8080808080808080;

x >>= 7; r |= x;
x >>= 7; r |= x;
x >>= 7; r |= x;
x >>= 7; r |= x;
x >>= 7; r |= x;
x >>= 7; r |= x;
x >>= 7; r |= x;
x >>= 7; r |= x;
return r;

我不確定哪個在實踐中會表現得更好,盡管我傾向於在第一個上下注 - 第二個可能產生更短的代碼,但具有長的依賴鏈。

首先,你真的不需要這么多操作。 您可以一次執行多個操作:

x = (x >> 7) & 0x0101010101010101; // 0x0101010101010101
x |= x >> 28;                      // 0x????????11111111
x |= x >> 14;                      // 0x????????????5555
x |= x >>  7;                      // 0x??????????????FF
return x & 0xFF;

另一種方法是使用modulo進行橫向添加。 首先要注意的是x % n是基數n+1中的數字之和,因此如果n+12^k ,則添加k位組。 如果你從上面的t = (x >> 7) & 0x0101010101010101 ,你想要對7位的組進行求和,因此t % 127將是解決方案。 但是t%127僅適用於高達126的結果.0x8080808080808080以上任何內容都會產生錯誤的結果。 我嘗試了一些修正,沒有一個容易。

試圖使用modulo將我們置於只有前一算法的最后一步的情況下才有可能。 我們想要的是保持兩個不太重要的位,然后得到另一個的總和,按14分組。所以

ull t = (x & 0x8080808080808080) >> 7;
ull u = (t & 3) | (((t>>2) % 0x3FFF) << 2);
return (u | (u>>7)) & 0xFF;

但是t >> 2是t / 4而<< 2乘以4.如果我們有(a % b)*c == (a*c % b*c) ,那么(((t>>2) % 0x3FFF) << 2)(t & ~3) % 0xFFFC 但是,如果小於c,我們還有a + b%c =(a + b)%c的事實。 所以我們只有u = t % FFFC 贈送:

ull t = ((x & 0x8080808080808080) >> 7) % 0xFFFC;
return (t | (t>>7)) & 0xFF;

這似乎有效:

return (x & 0x8080808080808080) % 127;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM