Хранение набора 3-битных двоичных данных с помощью PHP - PullRequest
2 голосов
/ 27 августа 2010

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

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

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

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

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

Спасибо

Ответы [ 5 ]

1 голос
/ 30 августа 2010

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

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

Но, придерживаясь темы, я предполагаю, что лучшее 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 + az дает вам 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-битными или битовыми логическими решениями), но это усложняет ситуацию в долгосрочной перспективе - возможно, больше проблем, чем стоит.

1 голос
/ 27 августа 2010

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

1 голос
/ 27 августа 2010

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

0 голосов
/ 27 августа 2010

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

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

0 голосов
/ 27 августа 2010

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

...