Хранение набора 3-битных двоичных данных с помощью PHP

Моя программа PHP работает с массивом значений от 0 до 7. Я пытаюсь найти наиболее эффективный способ хранения этих значений в PHP. Под наиболее эффективным я подразумеваю использование меньшего количества битов.

Понятно, что для каждого значения требуется только 3 бита памяти (от b000=0 до b111=7). Но как наиболее эффективно хранить эти 3-битные значения в двоичной строке?

Я не знаю заранее, сколько 3-битных значений мне нужно будет хранить или восстанавливать, но их может быть много, поэтому 64-битных явно недостаточно.

Я искал pack() и unpack(): я мог бы хранить два значения в каждом байте и использовать пакет ('C', $twoValues), но я все еще теряю 2 бита.

Это будет работать ? Есть ли более эффективный способ хранения этих значений?

Спасибо


person analogue    schedule 26.08.2010    source источник
comment
Вы не можете хранить вещи в PHP. Вы говорите об их сжатии в памяти во время работы с ними? Будете ли вы загружать их из базы данных?   -  person meagar    schedule 30.08.2010
comment
Да, я говорю об их сжатии в памяти, чтобы отправить их в мой механизм хранения, какой бы он ни был.   -  person analogue    schedule 31.08.2010


Ответы (5)


Вы не спросили, была ли это хорошей идеей - как многие предположили, ваша выгода от такого сжатия пространства легко теряется в дополнительной обработке - но это другая тема :)

Вы также не упоминаете, где вы храните данные после. Каким бы ни было это место хранения/механизм, у него могут быть дополнительные условия и специализированные типы (например, база данных имеет формат двоичного столбца, может иметь формат столбца байтов, может даже поддерживать хранение битов и т. д.).

Но, придерживаясь темы, я думаю, что лучшее 3-битное хранилище - это откусывание (с потерей одного бита), и я полагаю, что я бы объединил два откусывания в байт (в целом потеряв два бита). Да, вы теряете два бита (если это ключ), но просто объединить два значения, чтобы ваши накладные расходы на обработку были относительно небольшими:

$byte=$val1*7+$val2;
$val2=$byte%7;$val1=($byte-$val2)/7;

Если байт недоступен, вы можете объединить их, чтобы получить 16 (4 сохраненных), 32 (8), 64 (16) битных целых числа. Вы также можете сформировать массив этих значений для большего объема памяти.

Я бы посчитал приведенное выше более удобочитаемым для человека, но вы также можете использовать битовую логику для объединения и разделения значений:

$combinedbyte=$val1<<3|$val2;
$val2=$combinedbyte&7;$val1=($combinedbyte&56)>>3);

(Это фактически то, что делают команды PACK/UNPACK)

В качестве альтернативы вы можете кодировать в символы, поскольку в ASCII первые несколько защищены, вы также можете начать с A (A-Z+6 punc+a-z дает вам 58, когда вам нужно только 49 для хранения ваших двух значений).

$char=chr(($val1*7+$val2)+65); //ord('A')=65
$val2=(ord($char)-65)%7;$val1=(ord($char)-65-$val2)/7;

Последовательность этих закодированных символов может быть сохранена в виде массива или в строке с завершающим нулем.

ПРИМЕЧАНИЕ. В случае, скажем, 64-битных целых чисел выше, мы храним 3 бита в 4, поэтому получаем 64/4 = 16 ячеек памяти. Это означает, что мы теряем еще 16 бит (по 1 на место), поэтому у вас может возникнуть соблазн добавить еще 5 значений, всего 21 (21 * 3 = 63 бита, только 1 потерян). Это, безусловно, возможно (с целочисленной математикой - хотя большинство экземпляров PHP не работают с 64-битными или битовыми логическими решениями), но это усложняет ситуацию в долгосрочной перспективе - вероятно, больше проблем, чем того стоит.

person Rudu    schedule 30.08.2010
comment
Я именно так и сделал, но более уродливо :) Спасибо - person analogue; 31.08.2010

Лучший способ — хранить их как целые числа и не заниматься упаковкой по крупицам. Если у вас нет фактической инженерной причины, по которой вам нужно хранить их в виде 3-битных значений (например, для взаимодействия с оборудованием), вы просто просите головную боль. Имейте в виду, особенно для нечетных размеров битов, к которым становится довольно сложно получить прямой доступ, если вы это сделаете. И если вы вставите эти значения в базу данных, вы не сможете искать или индексировать значения, упакованные таким образом. Храните их как целые числа или, если в базе данных, возможно, короткое целое число или байт.

person GrandmasterB    schedule 26.08.2010

Такая техника необходима только в том случае, если у вас будет хотя бы полмиллиарда таких. Подумайте об этом, ЦП должен будет иметь данные в одном регистре, маску в другом и И их только для того, чтобы получить ваше значение. Теперь представьте, что вы перебираете список из них, который достаточно длинный, чтобы оправдать такой метод экономии места. На 50% меньше места и на порядок медленнее.

person Novikov    schedule 26.08.2010

Глядя на http://php.net/manual/en/language.types.php, вы должны хранить их как целые числа. Однако вопрос заключается в том, позволять ли одному целочисленному значению представлять множество 3-битных значений или нет. Первый более сложен, но требует меньше памяти, тогда как первый — наоборот. Если у вас нет крайней необходимости уменьшать объем используемой памяти, я бы предложил последнее (используйте одно целое число для одного 3-битного значения).

Основная проблема с хранением множества 3-битных значений в одном целом числе заключается в том, чтобы выяснить, сколько 3-битных значений существует. Вы можете использовать массив целых чисел, а затем иметь дополнительное целое число, которое указывает общее количество 3-битных значений. Однако, как указано в руководстве, количество битов, используемых для целочисленного значения, зависит от платформы. Таким образом, вам нужно знать, является ли целое число 32-битным или 64-битным, иначе вы можете попытаться сохранить слишком много значений и потерять данные, или вы рискуете использовать больше памяти, чем необходимо (что было бы плохо, поскольку вы стремитесь использовать как можно меньше памяти).

person gablin    schedule 26.08.2010

Я бы преобразовал каждое целое число в двоичное, объединил их все, а затем разделил полученную строку на байты. Каждый байт будет иметь значение 0-255, поэтому его можно сохранить как отдельный символ.

person Tim    schedule 26.08.2010
comment
Разве вы не имеете в виду, что каждый байт будет 0-255? Бит может хранить только 2 значения. ^^ - person gablin; 27.08.2010