簡體   English   中英

將無符號字符8位轉換為實際數字的最快方法

[英]Fastest way to convert unsigned char 8 bits to actual numbers

我正在使用一個unsigned char來存儲8個標志。 每個標志代表一個立方體的角。 因此, 00000001將是角1 01000100將是角3和7等。我當前的解決方案是將&的結果分別為1,2,4,8,16,32,64和128,檢查結果是否不為零並存儲角。 也就是說, if (result & 1) corners.push_back(1); 我是否有可能擺脫該“如果”陳述? 我希望可以使用按位運算符來擺脫它,但是我什么也沒想到。

關於為什么要擺脫if語句的一些背景知識。 多維數據集實際上是體素,它是尺寸至少為512x512x512的網格的一部分。 那是超過1.34億個體素。 我正在對每個Voxel進行計算(嗯,不完全是,但是由於這里無關緊要,所以我不會贅述),這是很多計算。 而且我需要每幀執行這些計算。 每個函數調用的微小速度提升都將有助於這些計算量。 為了給您一個想法,我的算法(在某個時候)需要確定浮點數是負數,正數還是零(有一定誤差)。 我那里有if語句,大於/小於檢查。 我用快速浮點數將其替換為int函數,並節省了四分之一秒。 目前,128x128x128網格中的每個幀花費的時間超過4秒。

我會考慮完全采用另一種方法:標志的不同組合只有256種可能性。 預先計算256個向量,並根據需要對其進行索引。

std::vector<std::vector<int> > corners(256);
for (int i = 0; i < 256; ++i) {
    std::vector<int>& v = corners[i];
    if (i & 1) v.push_back(1);
    if (i & 2) v.push_back(2);
    if (i & 4) v.push_back(4);
    if (i & 8) v.push_back(8);
    if (i & 16) v.push_back(16);
    if (i & 32) v.push_back(32);
    if (i & 64) v.push_back(64);
    if (i & 128) v.push_back(128);
}

for (int i = 0; i < NumVoxels(); ++i) {
    unsigned char flags = GetFlags(i);
    const std::vector& v = corners[flags];

    ... // do whatever with v
}

這樣可以避免所有條件, 讓push_back調用new ,無論如何我都認為它會更昂貴。

黑客的喜悅 ,第一頁:

x & (-x) // isolates the lowest set bit
x & (x - 1) // clears the lowest set bit

內聯push_back方法也將有所幫助(更好地創建一個將所有標志一起接收的函數)。

通常,如果您需要性能,則應考慮到整個系統的設計。 也許如果您發布更多代碼,將更容易獲得幫助。

編輯:這是一個好主意:

unsigned char LOG2_LUT[256] = {...};
int t;
switch (count_set_bits(flags)){
    case 8:     t = flags; 
                flags &= (flags - 1);       // clearing a bit that was set
                t ^= flags;                 // getting the changed bit
                corners.push_back(LOG2_LUT[t]);
    case 7:     t = flags; 
                flags &= (flags - 1);       
                t ^= flags;                 
                corners.push_back(LOG2_LUT[t]);
    case 6:     t = flags; 
                flags &= (flags - 1);       
                t ^= flags;                 
                corners.push_back(LOG2_LUT[t]);
    // etc...
};

count_set_bits()是一個非常知名的函數: http : count_set_bits()

如果在設置了該位的情況下需要執行某些操作,而在沒有設置該位的情況下則需要執行某些操作,那么看來您必須在某處具有某種條件。 如果可以某種方式將其表示為計算,則可以這樣解決,例如:

numCorners = ((result >> 0) & 1) + ((result >> 1) & 1) + ((result >> 2) & 1) + ...

嗯...我不確定您會比現在使用的按位運算符快得多。 corners.push_back方法在做什么?

編輯:這應該是一條注釋> _>我的壞...

有一種方法,它不是“漂亮”的,但可以。

(result & 1)   && corners.push_back(1);
(result & 2)   && corners.push_back(2);
(result & 4)   && corners.push_back(3);
(result & 8)   && corners.push_back(4);
(result & 16)  && corners.push_back(5);
(result & 32)  && corners.push_back(6);
(result & 64)  && corners.push_back(7);
(result & 128) && corners.push_back(8);

它使用C ++語言的一個鮮為人知的功能:布爾快捷方式。

我在OpenTTD代碼中注意到了類似的算法。 事實證明這是完全沒有用的:通過分解這樣的數字可以更快地完成工作。 取而代之的是,通過對字節的位進行迭代來替換對現在的vector<>進行的迭代。 這對緩存更加友好。

unsigned char flags = Foo(); // the value you didn't put in a vector<>
for (unsigned char c = (UCHAR_MAX >> 1) + 1; c !=0 ; c >>= 1)
{
  if (flags & c) 
    Bar(flags&c);
}

暫無
暫無

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

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