[英]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.