簡體   English   中英

在C ++中將十六進制轉換為整數的最快方法是什么?

[英]What's the fastest way to convert hex to integer in C++?

我正在嘗試盡快將十六進制char轉換為整數。

這只是一行: int x = atoi(hex.c_str);

有更快的方法嗎?

在這里,我嘗試了一種更加動態的方法,而且速度稍快一些。

int hextoint(char number) {
    if (number == '0') {
        return 0;
    }
    if (number == '1') {
        return 1;
    }
    if (number == '2') {
        return 2;
    }
    /*
     *  3 through 8
     */
    if (number == '9') {
        return 9;
    }
    if (number == 'a') {
        return 10;
    }
    if (number == 'b') {
        return 11;
    }
    if (number == 'c') {
        return 12;
    }
    if (number == 'd') {
        return 13;
    }
    if (number == 'e') {
        return 14;
    }
    if (number == 'f') {
        return 15;
    }
    return -1;
}

提議的解決方案比OP的if-else更快:

  • 無序地圖查找表

如果您的輸入字符串始終是十六進制數字,則可以將查找表定義為unordered_map

std::unordered_map<char, int> table {
{'0', 0}, {'1', 1}, {'2', 2},
{'3', 3}, {'4', 4}, {'5', 5},
{'6', 6}, {'7', 7}, {'8', 8},
{'9', 9}, {'a', 10}, {'A', 10},
{'b', 11}, {'B', 11}, {'c', 12},
{'C', 12}, {'d', 13}, {'D', 13},
{'e', 14}, {'E', 14}, {'f', 15},
{'F', 15}, {'x', 0}, {'X', 0}};

int hextoint(char number) {
  return table[(std::size_t)number];
}
  • 查找表作為用戶constexpr文字(C ++ 14)

或者如果你想要更快的東西而不是unordered_map你可以使用具有用戶文字類型的新C ++ 14工具,並在編譯時將你的表定義為文字類型:

struct Table {
  long long tab[128];
  constexpr Table() : tab {} {
    tab['1'] = 1;
    tab['2'] = 2;
    tab['3'] = 3;
    tab['4'] = 4;
    tab['5'] = 5;
    tab['6'] = 6;
    tab['7'] = 7;
    tab['8'] = 8;
    tab['9'] = 9;
    tab['a'] = 10;
    tab['A'] = 10;
    tab['b'] = 11;
    tab['B'] = 11;
    tab['c'] = 12;
    tab['C'] = 12;
    tab['d'] = 13;
    tab['D'] = 13;
    tab['e'] = 14;
    tab['E'] = 14;
    tab['f'] = 15;
    tab['F'] = 15;
  }
  constexpr long long operator[](char const idx) const { return tab[(std::size_t) idx]; } 
} constexpr table;

constexpr int hextoint(char number) {
  return table[(std::size_t)number];
}

現場演示

基准:

我使用最近在isocpp.org上發布的Nikos Athanasiou編寫的代碼運行基准測試,作為C ++微基准測試的提議方法。

比較的算法是:

1. OP的原始if-else

 long long hextoint3(char number) { if(number == '0') return 0; if(number == '1') return 1; if(number == '2') return 2; if(number == '3') return 3; if(number == '4') return 4; if(number == '5') return 5; if(number == '6') return 6; if(number == '7') return 7; if(number == '8') return 8; if(number == '9') return 9; if(number == 'a' || number == 'A') return 10; if(number == 'b' || number == 'B') return 11; if(number == 'c' || number == 'C') return 12; if(number == 'd' || number == 'D') return 13; if(number == 'e' || number == 'E') return 14; if(number == 'f' || number == 'F') return 15; return 0; } 

2. Christophe提出的緊湊if-else:

 long long hextoint(char number) { if (number >= '0' && number <= '9') return number - '0'; else if (number >= 'a' && number <= 'f') return number - 'a' + 0x0a; else if (number >= 'A' && number <= 'F') return number - 'A' + 0X0a; else return 0; } 

3.修正了由g24l提出的處理大寫字母輸入的三元運算符版本:

 long long hextoint(char in) { int const x = in; return (x <= 57)? x - 48 : (x <= 70)? (x - 65) + 0x0a : (x - 97) + 0x0a; } 

4.查找表( unordered_map ):

 long long hextoint(char number) { return table[(std::size_t)number]; } 

其中table是前面顯示的無序映射。

5.查找表(用戶constexpr文字):

 long long hextoint(char number) { return table[(std::size_t)number]; } 

表是用戶定義的文字,如上所示。

實驗設置

我定義了一個將輸入十六進制字符串轉換為整數的函數:

 long long hexstrtoint(std::string const &str, long long(*f)(char)) { long long ret = 0; for(int j(1), i(str.size() - 1); i >= 0; --i, j *= 16) { ret += (j * f(str[i])); } return ret; } 

我還定義了一個用隨機十六進制字符串填充字符串向量的函數:

 std::vector<std::string> populate_vec(int const N) { random_device rd; mt19937 eng{ rd() }; uniform_int_distribution<long long> distr(0, std::numeric_limits<long long>::max() - 1); std::vector<std::string> out(N); for(int i(0); i < N; ++i) { out[i] = int_to_hex(distr(eng)); } return out; } 

我創建了分別填充50000,100000,150000,200000和250000隨機十六進制字符串的向量。 然后,對於每個算法,我運行100個實驗並平均時間結果。

編譯器是GCC 5.2版,帶有優化選項-O3

結果:

在此輸入圖像描述

在此輸入圖像描述

在此輸入圖像描述

在此輸入圖像描述

在此輸入圖像描述

在此輸入圖像描述

討論

從結果我們可以得出結論,對於這些實驗設置,建議的表方法優於所有其他方法。 if-else方法到目前為止是最糟糕的,因為unordered_map雖然贏得了if-else方法,但它明顯慢於其他提議的方法。

編輯:

stgatilov提出的方法的結果,按位運算:

 long long hextoint(char x) { int b = uint8_t(x); int maskLetter = (('9' - b) >> 31); int maskSmall = (('Z' - b) >> 31); int offset = '0' + (maskLetter & int('A' - '0' - 10)) + (maskSmall & int('a' - 'A')); return b - offset; } 

在此輸入圖像描述

編輯:

我還針對table方法測試了g24l的原始代碼:

 long long hextoint(char in) { long long const x = in; return x < 58? x - 48 : x - 87; } 

請注意,此方法不處理大寫字母ABCDEF

結果:

在此輸入圖像描述

表格方法仍然更快。

對於不同的系統,這個問題顯然可能有不同的答案,從這個意義上講,它從一開始就是不適合的。 例如,i486沒有管道,奔騰沒有SSE。

要問的正確問題是:“ X系統中將單個字符十六進制轉換為dec的最快方法是什么,例如i686 ”。

在這里的方法中,對於具有多級流水線的系統,其答案實際上是相同或非常非常非常相同。 任何沒有管道的系統都會向查找表方法(LUT)彎曲,但如果內存訪問速度慢,則條件方法(CEV)或按位評估方法(BEV)可能會受益於xor與負載的速度。給定CPU。

(CEV)將來自寄存器的比較和條件移動分解為2個加載有效地址,不易於誤預測 所有這些命令在奔騰管道中都是可配對的。 所以他們實際上進入了一個周期。

  8d 57 d0                lea    -0x30(%rdi),%edx
  83 ff 39                cmp    $0x39,%edi
  8d 47 a9                lea    -0x57(%rdi),%eax
  0f 4e c2                cmovle %edx,%eax

(LUT)分解為寄存器之間的mov和來自數據相關存儲器位置的mov以及用於對齊的一些nops,並且應該采用最小的1個周期。 如前所述,只有數據依賴。

  48 63 ff                movslq %edi,%rdi
  8b 04 bd 00 1d 40 00    mov    0x401d00(,%rdi,4),%eax

(BEV)是一個不同的野獸,因為它實際上需要2個mov + 2個xors + 1和一個條件mov。 這些也可以很好地流水線化。

  89 fa                   mov    %edi,%edx
  89 f8                   mov    %edi,%eax
  83 f2 57                xor    $0x57,%edx
  83 f0 30                xor    $0x30,%eax
  83 e7 40                and    $0x40,%edi
  0f 45 c2                cmovne %edx,%eax

當然,這是一個非常罕見的場合,應用程序關鍵(可能是Mars Pathfinder是一個候選者)只轉換一個信號char 相反,人們會期望通過實際制作循環並調用該函數來轉換更大的字符串。

因此,在這種情況下,更好的可矢量化的代碼是勝利者。 LUT沒有矢量化,BEV和CEV具有更好的行為。 一般來說,這樣的微優化不會讓你隨處可見,編寫你的代碼並讓它們直播(即讓編譯器運行)。

所以我實際上已經在這個意義上構建了一些測試,它們可以在任何具有c ++ 11編譯器和隨機設備源的系統上輕松重現 ,例如任何* nix系統。 如果一個人不允許矢量化-O2 CEV / LUT幾乎相等,但一旦設置-O3 ,編寫更易分解的代碼的優勢就顯示出差異。

總而言之, 如果你有一個舊的編譯器使用LUT,如果你的系統是低端或舊的考慮BEV,否則編譯器將超越你,你應該使用CEV


問題 :問題是從字符集{0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}轉換為{的集合0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}。 沒有正在考慮的大寫字母。

我們的想法是利用分段中ascii表的線性度。

[簡單易行]:條件評估 - > CEV

int decfromhex(int const x)
{
return x<58?x-48:x-87;
}

[臟和復雜]:按位評估 - > BEV

int decfromhex(int const x)
{
return 9*(x&16)+( x & 0xf  );
}

[編譯時間]:模板條件評估 - > TCV

template<char n> int decfromhex()
{
  int constexpr x = n;
  return x<58 ? x-48 : x -87;
}

[查找表]:查找表 - > LUT

int decfromhex(char n)
{
static int constexpr x[255]={
           // fill everything with invalid, e.g. -1 except places\
           // 48-57 and 97-102 where you place 0..15 
           };
return x[n];
}

在所有,最后似乎第一次看是最快的。 第二個是僅在編譯時和常量表達式。

[結果]請確認 ): * BEV是最快的,處理大小寫字母 ,但僅限於不處理大寫字母的CEV 隨着字符串大小的增加,LUT變得比CEV和BEV都慢。

str-size 16-12384的示例性結果可以在下面找到( 越低越好

在此輸入圖像描述

顯示平均時間(100次運行)。 氣泡的大小是正常的誤差。

可以使用運行測試的腳本。


已經對一組隨機生成的字符串上的conditional CEVbitwise BEVlookup table LUT執行了測試。 測試相當簡單,來自:

測試源代碼

這些是可以驗證的:

  1. 每次輸入字符串的本地副本都放在本地緩沖區中。
  2. 保留結果的本地副本,然后將其復制到堆中以進行每個字符串測試
  3. 僅提取對字符串操作的時間的持續時間
  4. 統一的方法 ,沒有復雜的機械和包裝/周圍的代碼適合其他情況。
  5. 沒有采樣使用整個時序
  6. 執行CPU預熱
  7. 在測試之間進行休眠以允許編組代碼,使得一個測試不利用先前的測試。
  8. 編譯使用g++ -std=c++11 -O3 -march=native dectohex.cpp -o d2h
  9. 使用taskset -c 0 d2h 啟動
  10. 沒有線程依賴或多線程
  11. 實際上正在使用結果,以避免任何類型的循環優化

作為附注,我在練習版本3中看到使用較舊的c ++ 98編譯器要快得多。

[BOTTOM LINE] :毫無顧慮地使用CEV ,除非您在編譯時知道您的變量,您可以使用版本TCV 只有在每個用例評估的重要性能之后才能使用LUT ,並且可能在較舊的編譯器之后使用。 另一種情況是你的集合較大,即{0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,A,B,C,D, E,F}。 這也可以實現。 最后,如果你是飢腸轆轆,請使用BEV

unordered_map的結果已被刪除,因為它們太慢而無法比較,或者最好的情況可能與LUT解決方案一樣快。

我的個人電腦上的字符串大小為12384/256和100個字符串的結果:

 g++ -DS=2 -DSTR_SIZE=256 -DSET_SIZE=100 -DUNITS=nanoseconds -O3 -std=c++11 -march=native dectohex.cpp -o d2h && taskset -c 0 ./d2h
sign: -2709
-------------------------------------------------------------------
(CEV) Total: 185568 nanoseconds - mean: 323.98 nanoseconds  error: 88.2699 nanoseconds
(BEV) Total: 185568 nanoseconds - mean: 337.68 nanoseconds  error: 113.784 nanoseconds
(LUT) Total: 229612 nanoseconds - mean: 667.89 nanoseconds  error: 441.824 nanoseconds
-------------------------------------------------------------------


g++ -DS=2 -DSTR_SIZE=12384 -DSET_SIZE=100 -DUNITS=nanoseconds -O3 -std=c++11 -march=native hextodec.cpp -o d2h && taskset -c 0 ./h2d

-------------------------------------------------------------------
(CEV) Total: 5539902 nanoseconds - mean: 6229.1 nanoseconds error: 1052.45 nanoseconds
(BEV) Total: 5539902 nanoseconds - mean: 5911.64 nanoseconds    error: 1547.27 nanoseconds
(LUT) Total: 6346209 nanoseconds - mean: 14384.6 nanoseconds    error: 1795.71 nanoseconds
-------------------------------------------------------------------
Precision: 1 ns

將GCC 4.9.3系統的結果編譯為金屬而不將系統加載到大小為256/12384的字符串和100個字符串上

g++ -DS=2 -DSTR_SIZE=256 -DSET_SIZE=100 -DUNITS=nanoseconds -O3 -std=c++11 -march=native dectohex.cpp -o d2h && taskset -c 0 ./d2h
sign: -2882
-------------------------------------------------------------------
(CEV) Total: 237449 nanoseconds - mean: 444.17 nanoseconds  error: 117.337 nanoseconds
(BEV) Total: 237449 nanoseconds - mean: 413.59 nanoseconds  error: 109.973 nanoseconds
(LUT) Total: 262469 nanoseconds - mean: 731.61 nanoseconds  error: 11.7507 nanoseconds
-------------------------------------------------------------------
Precision: 1 ns


g++ -DS=2 -DSTR_SIZE=12384 -DSET_SIZE=100 -DUNITS=nanoseconds -O3 -std=c++11 -march=native dectohex.cpp -o d2h && taskset -c 0 ./d2h
sign: -137532
-------------------------------------------------------------------
(CEV) Total: 6834796 nanoseconds - mean: 9138.93 nanoseconds    error: 144.134 nanoseconds
(BEV) Total: 6834796 nanoseconds - mean: 8588.37 nanoseconds    error: 4479.47 nanoseconds
(LUT) Total: 8395700 nanoseconds - mean: 24171.1 nanoseconds    error: 1600.46 nanoseconds
-------------------------------------------------------------------
Precision: 1 ns

[如何閱讀結果]

平均值顯示在計算給定大小的字符串所需的微秒上。

給出每次測試的總時間。 均值計算為計算一個字符串的時間總和/總數(該區域中沒有其他代碼但可以進行矢量化,這沒關系)。 誤差是時間的標准偏差。

平均值告訴我們平均應該得到什么,以及錯誤在正常情況下的時間。 在這種情況下,只有當它很小時,這才是公平的誤差測量(否則我們應該使用適合於正分布的東西)。 高速緩存未命中處理器調度和許多其他因素的情況下,通常應該期望高錯誤。


代碼有一個唯一的宏定義為運行測試,允許定義編譯時變量來設置測試,並打印完整的信息,如:

g++ -DS=2 -DSTR_SIZE=64 -DSET_SIZE=1000 -DUNITS=nanoseconds -O3 -std=c++11 -march=native dectohex.cpp -o d2h && taskset -c 0 ./d2h
sign: -6935
-------------------------------------------------------------------
(CEV) Total: 947378 nanoseconds - mean: 300.871 nanoseconds error: 442.644 nanoseconds
(BEV) Total: 947378 nanoseconds - mean: 277.866 nanoseconds error: 43.7235 nanoseconds
(LUT) Total: 1040307 nanoseconds - mean: 375.877 nanoseconds    error: 14.5706 nanoseconds
-------------------------------------------------------------------

例如,在大小為256的str上以2sec暫停運行測試,總共10000不同的字符串,輸出定時為double precision ,並以nanoseconds為單位,以下命令編譯並運行測試。

g++ -DS=2 -DSTR_SIZE=256 -DSET_SIZE=10000 -DUTYPE=double -DUNITS=nanoseconds -O3 -std=c++11 -march=native dectohex.cpp -o d2h && taskset -c 0 ./d2h

嗯,這是一個奇怪的問題。 將單個十六進制字符轉換為整數是如此之快,以至於很難判斷哪個更快,因為所有方法幾乎可能比您編寫的代碼更快以便使用它們=)

我會假設以下事項:

  1. 我們有一個現代的x86(64)CPU。
  2. 輸入字符的ASCII碼存儲在通用寄存器中,例如存儲在eax
  3. 必須在通用寄存器中獲取輸出整數。
  4. 輸入字符保證是有效的十六進制數字(16個案例之一)。

現在有幾種解決問題的方法:第一種基於查找,第二種基於三元運算符,最后一種基於位運算:

int hextoint_lut(char x) {
    static char lut[256] = {???};
    return lut[uint8_t(x)];
}

int hextoint_cond(char x) {
    uint32_t dig = x - '0';
    uint32_t alp = dig + ('0' - 'a' + 10);
    return dig <= 9U ? dig : alp;
}
int hextoint_cond2(char x) {
    uint32_t offset = (uint8_t(x) <= uint8_t('9') ? '0' : 'a' - 10);
    return uint8_t(x) - offset;
}

int hextoint_bit(char x) {
    int b = uint8_t(x);
    int mask = (('9' - b) >> 31);
    int offset = '0' + (mask & int('a' - '0' - 10));
    return b - offset;
}

以下是生成的相應裝配清單(僅顯示相關部件):

;hextoint_lut;
movsx   eax, BYTE PTR [rax+rcx]   ; just load the byte =)

;hextoint_cond;
sub edx, 48                       ; subtract '0'
cmp edx, 9                        ; compare to '9'
lea eax, DWORD PTR [rdx-39]       ; add ('0' - 'a' + 10)
cmovbe  eax, edx                  ; choose between two cases in branchless way

;hextoint_cond2;                  ; (modified slightly)
mov eax, 48                       
mov edx, 87                       ; set two offsets to registers
cmp ecx, 57                       ; compare with '9'
cmovbe  edx, eax                  ; choose one offset
sub ecx, edx                      ; subtract the offset

;hextoint_bit;
mov ecx, 57                       ; load '9'
sub ecx, eax                      ; get '9' - x
sar ecx, 31                       ; convert to mask if negative
and ecx, 39                       ; set to 39 (for x > '9')
sub eax, ecx                      ; subtract 39 or 0
sub eax, 48                       ; subtract '0'

分析

我將嘗試估算吞吐量意義上每種方法所采用的周期數,這實質上是一次處理大量數字時每一個輸入數所花費的時間。 以Sandy Bridge架構為例。

hextoint_lut函數由單個內存加載組成,在端口2或3上占用1個uop。這兩個端口都專用於內存加載,它們內部也有地址計算,能夠執行rax+rcx而無需額外成本。 有兩個這樣的端口,每個端口可以在一個周期內做一個uop。 所以據說這個版本需要0.5個時鍾。 如果我們必須從內存加載輸入數,那么每個值需要多一個內存負載,因此總成本為1個時鍾。

hextoint_cond版本有4條指令,但cmov分為兩個單獨的cmov 因此總共有5個uop,每個都可以在三個算術端口0,1和5中的任何一個上進行處理。因此可能需要5/3個周期時間。 請注意,內存加載端口是空閑的,因此即使您必須從內存加載輸入值,時間也不會增加。

hextoint_cond2版本有5條指令。 但是在緊密循環中,常量可以預加載到寄存器,因此只有比較,cmov和減法。 它們總共為4個uop,每個值提供4/3個周期(即使讀取內存)。

hextoint_bit版本是一個保證沒有分支和查找的解決方案,如果您不想總是檢查編譯器是否生成了cmov指令,這很方便。 第一個mov是自由的,因為常量可以在緊密循環中預加載。 其余的是5個算術指令,在端口0,1,5中有5個uop。因此它應該需要5/3個周期(即使存儲器讀取)。

基准

我已經為上述C ++函數執行了基准測試。 在基准測試中,生成64 KB的隨機數據,然后每個函數在此數據上運行多次。 所有結果都添加到校驗和中,以確保編譯器不會刪除代碼。 使用手動8x展開。 我在Ivy Bridge 3.4 Ghz核心上進行了測試,這與Sandy Bridge非常相似。 每個輸出字符串包含:函數名稱,基准測試所用的總時間,每個輸入值的周期數,所有輸出的總和。

基准代碼

MSVC2013 x64 /O2:
hextoint_lut: 0.741 sec, 1.2 cycles  (check: -1022918656)
hextoint_cond: 1.925 sec, 3.0 cycles  (check: -1022918656)
hextoint_cond2: 1.660 sec, 2.6 cycles  (check: -1022918656)
hextoint_bit: 1.400 sec, 2.2 cycles  (check: -1022918656)

GCC 4.8.3 x64 -O3 -fno-tree-vectorize
hextoint_lut: 0.702 sec, 1.1 cycles  (check: -1114112000)
hextoint_cond: 1.513 sec, 2.4 cycles  (check: -1114112000)
hextoint_cond2: 2.543 sec, 4.0 cycles  (check: -1114112000)
hextoint_bit: 1.544 sec, 2.4 cycles  (check: -1114112000)

GCC 4.8.3 x64 -O3
hextoint_lut: 0.702 sec, 1.1 cycles  (check: -1114112000)
hextoint_cond: 0.717 sec, 1.1 cycles  (check: -1114112000)
hextoint_cond2: 0.468 sec, 0.7 cycles  (check: -1114112000)
hextoint_bit: 0.577 sec, 0.9 cycles  (check: -1114112000)

顯然,LUT方法每個值需要一個周期(如預測的那樣)。 其他方法通常需要每個值2.2到2.6個周期。 在GCC的情況下, hextoint_cond2很慢,因為編譯器使用cmp + sbb +和magic而不是所需的cmov指令。 另請注意,默認情況下,GCC會對大多數方法進行矢量化(最后一段),這提供了比不可歸一化的LUT方法更快的結果。 請注意,手動矢量化會提供更大的提升。

討論

請注意,使用普通條件跳轉而不是cmov hextoint_cond將具有分支。 假設隨機輸入十六進制數字,它幾乎總是會被錯誤預測。 因此,我認為表現會很糟糕。

我已經分析了吞吐量性能。 但是如果我們必須處理大量的輸入值,那么我們肯定應該對轉換進行矢量化以獲得更好的速度。 hextoint_cond可以使用SSE以非常簡單的方式進行矢量化。 它允許僅使用4條指令處理16個字節到16個字節,我認為大約需要2個周期。

請注意,為了查看性能差異,您必須確保所有輸入值都適合緩存(L1是最佳情況)。 如果從主內存中讀取輸入數據,即使std::atoi與所考慮的方法同樣快速=)

此外,您應該將主循環展開4x甚至8x以獲得最佳性能(以消除循環開銷)。 您可能已經注意到,兩種方法的速度在很大程度上取決於代碼周圍的操作。 例如,添加內存負載會使第一種方法所花費的時間加倍,但不會影響其他方法。

PS很可能你真的不需要優化它。

假設你的函數被調用一個有效的十六進制數字,它將平均花費至少8個比較操作(和perhap的7次跳轉)。 很貴。

另一種選擇是更緊湊:

if (number >= '0' && number<='9') 
    return number-'0';
else if (number >= 'a' && number <='f') 
    return number-'a'+0x0a; 
else return -1; 

另一個替代方案是使用查找表 (交易空間與速度),您只需初始化一次,然后直接訪問:

if (number>=0) 
   return mytable[number]; 
else return -1;   

如果你想一次轉換多個數字,你可以看一下這個問題

編輯:基准

根據艾克的觀察,我寫了一個小的非正式基准( 在線提供),你可以運行你最喜歡的編譯器。

結論:

  • 查找表始終是贏家
  • 該開關比if-chain更好。
  • 隨着msvc2015(發布),第二個最好的是我的緊湊版本,令人驚訝的是緊跟地圖版101010
  • 使用gcc on ideone,第二個是交換機版本,緊接着是緊湊版本。 在此輸入圖像描述

這是我最喜歡的hex-to-int代碼:

inline int htoi(int x) {
    return 9 * (x >> 6) + (x & 017);
}

它對字母不區分大小寫,即將返回“a”和“A”的正確結果。

如果您(或其他人)實際上正在轉換值數組,我制作了一個AVX2 SIMD編碼器和解碼器,其基准測試比最快的標量實現速度快〜12倍: https//github.com/zbjornson/fast-hex

16個十六進制值可方便地(兩次)放入YMM寄存器,因此您可以使用PSHUFB進行並行查找。 解碼有點困難,基於逐位操作。

暫無
暫無

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

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