В этом проекте мне нужно создать один огромный массив (надеюсь, я смогу создать его размером ~ 7,13e + 17, но эта цель еще впереди.)
Это требует создания выделенной структуры, типа цифрового дерева (или b-дерева ) с ключом, являющимся индексом, чтобы избежать больших выделений.
Большие выделения и особенно перераспределения могут привести к ненужной фрагментации памяти .Если вы разбиваете большой массив на более мелкие порции, тогда не только становится проще расширение массива, но и становится возможным представление разреженного массива.
NB ~7.13e+17
имеет длину около 60 бит.У вас даже есть оборудование, которое может поддерживать столько оперативной памяти?Не то, чтобы я внимательно следил за отраслью, но я кратко слышал об NUMA-арках с 58-битной адресной шиной, но ничего о 60-битных арках.три значения: 0, 1, 2.2.
Если ячейка может содержать только 3 значения (2.2 может быть представлено как 2), что составляет 2 бита информации.Это означает, что вы можете упаковать в значения uint32_t
16 и в значения uint64_t
32.
Вы можете попытаться найти существующую реализацию цифрового дерева (или свернуть свою собственную) и использовать в качестве верхнего ключабиты индекса.Остальные биты исходного индекса будут индексом в листе дерева, который будет массивом с упакованными значениями.В качестве примера использования std::map
вместо дерева, не проверено:
enum {
LS_BITS = 16,
MS_BITS = 64-LS_BITS
};
enum {
VALUE_BITS = 2,
VALUE_MASK = ((1<<VALUE_BITS)-1)
};
// this represents an array of `1<<LS_BITS` values
struct leaf_node {
uint64_t packed_data[ ((1<<LS_BITS)*VALUE_BITS) / (sizeof(uint64_t)*8) ];
};
// that should be a trie, to provide faster look-up
typedef std::map< uint64_t, leaf_node > big_array_type;
void
big_array_set_value( big_array_type &b, uint64_t index, uint64_t value )
{
leaf_node &n = b[index >> LS_BITS];
uint64_t li = index & ((1<<LS_BITS)-1);
li *= VALUE_BITS; // convert into bit offset
uint64_t &x = n.packed_data[ li / (sizeof(uint64_t)*8) ];
li %= (sizeof(uint64_t)*8);
x = (x & (VALUE_MASK<<li)) | (value << li);
}
int
big_array_get_value( big_array_type &b, uint64_t index, uint64_t value )
{
leaf_node &n = b[index >> LS_BITS];
uint64_t li = index & ((1<<LS_BITS)-1);
li *= VALUE_BITS; // convert into bit offset
uint64_t &x = n.packed_data[ li / (sizeof(uint64_t)*8) ];
li %= (sizeof(uint64_t)*8);
return (x >> li) & VALUE_MASK;
}
Таким образом, каждый по-прежнему тратит 0,5 бита информации, так как память составляет 2 бита, что позволяет 4 значениям, но используются только 3.Это также можно улучшить, но при гораздо более высоких затратах производительности доступа.