我創建一個數據結構來緊湊地表示小的整數的數組:從緊湊INT選擇一個隨機元素陣列
/*
* Compactly represents an array of N unsigned integers, where each one only
* requires B bits to store.
*/
template<uint32_t N, uint8_t B>
class __attribute__((packed)) small_int_array {
private:
static const uint32_t items_per_page = 64/B;
static const uint32_t num_pages = (N + items_per_page - 1)/items_per_page;
static const uint64_t mask_unit = (1UL << B) - 1;
struct helper_t {
uint32_t page;
uint8_t offset;
helper_t(uint32_t index) : page(index/items_per_page),
offset(index%items_per_page) {}
};
uint64_t _pages[num_pages];
public:
small_int_array() { memset(this, 0, sizeof(this)); }
uint8_t get(uint32_t index) const {
helper_t helper(index);
uint8_t shift = B*helper.offset;
return (_pages[helper.page] & (mask_unit << shift)) >> shift;
}
void set(uint32_t index, uint8_t value) {
helper_t helper(index);
uint8_t shift = B*helper.offset;
_pages[helper.page] &= ~0UL - (mask_unit << shift);
_pages[helper.page] |= ((uint64_t)value) << shift;
}
};
我然後實現這個特殊的方法:
/*
* Returns a uniformly random index such that get(index)==value.
* Returns -1 if no such index exists.
*/
int32_t get_random_index(uint8_t value) const {
int32_t candidates[N];
int size=0;
uint32_t index = 0;
for (int i=0; i<num_pages; ++i) {
uint64_t page = _pages[i];
for (int j=0; j<items_per_page; ++j) {
candidates[size] = index++;
if (index==N) break;
bool match = (page & mask_unit) == value;
size += match ? 1 : 0;
page = page >> B;
}
}
if (size==0) return -1;
return candidates[rand() % size];
}
此做什麼我想,但我想知道是否有更有效的實現使用位技巧來代替第二個for循環。只要尺寸不增加,我可以改變對象的位表示。
我使用N〜= 100和B = < 4。
這兩個嵌套循環是不是等同於枚舉函數'get' for index 0..max?如果是這樣,那麼只有一個循環可以做到這一點,當獲得結果與傳遞的值匹配時記錄候選者? – danh
@danh是的,這是等價的,並且可能會犧牲更多的算術運算來提高代碼的清晰度。 – dshin
得到的代碼看起來非常緊密,特別是如果你將它內聯在循環中。你也可以內聯helper()代碼,並且可能會找到一些額外的節省。 – danh