Есть ли практические ограничения на размер битовых масок?

Существует распространенный способ хранения нескольких значений в одной переменной с помощью битовой маски. Например, если у пользователя есть права на чтение, запись и выполнение для элемента, их можно преобразовать в одно число, произнеся read = 4 (2^2), write = 2 (2^1), execute = 1 (2^0), а затем сложив их вместе, чтобы получить 7.

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

Меня интересует, существует ли практический предел количества значений, которые вы можете хранить таким образом? Например, если число было больше 64, вы больше не могли использовать (64-битные) целые числа. Если бы это было так, что бы вы использовали? Как это повлияет на логику вашей программы (например, можно ли по-прежнему использовать побитовые сравнения)?

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

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
5
0
5 809
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Я использовал битовые маски в коде файловой системы, где битовая маска во много раз больше машинного слова. думайте об этом как о «массиве логических значений»;

(ведение журнала масок во флеш-памяти, если хотите знать)

многие компиляторы умеют это делать для тебя. Добавьте немного объектно-ориентированного кода, чтобы иметь типы, которые работают разумно, и тогда ваш код начнет выглядеть так, как будто он намерен, а не какой-то битовый удар.

Мои 2 цента.

Итак, вы предлагаете, возможно, сохранить его в базе данных как двоичное поле переменной длины (BLOB?), а затем при его обработке преобразовать в массив bools? это может сработать - какой тип данных вы должны использовать в БД?

nickf 07.10.2008 06:57

С 64-битным целым числом вы можете хранить значения до 2 ^ 64-1, 64 - это только 2 ^ 6. Так что да, есть предел, но если вам нужно более 64 флагов, мне было бы очень интересно узнать, что они все делали :)

О скольких штатах вам потенциально нужно подумать? Если у вас есть 64 потенциальных состояния, количество комбинаций, в которых они могут существовать, составляет полный размер 64-битного целого числа.

Если вам нужно беспокоиться о 128 флагах, то достаточно пары битовых векторов (2 ^ 64 * 2).

Добавление: в Programming Pearls подробно обсуждается использование битового массива длиной 10 ^ 7, реализованного в целых числах (для хранения используемых 800 чисел) - это очень быстро и очень подходит для задачи, описанной в этой главе.

да, я имел в виду «64 флага» (2 ^ 64), а не «64 комбинации» (2 ^ 6).

nickf 07.10.2008 06:55

Я подумал, что вы имели в виду, но хотел внести пояснение в свой ответ :)

warren 07.10.2008 06:58

Например, .NET использует массив целых чисел в качестве внутреннего хранилища для своего класса BitArray. Другого пути практически нет.

При этом в SQL вам потребуется более одного столбца (или использовать BLOBS) для хранения всех состояний.

Ответ принят как подходящий

С самого начала я бы написал функцию set_bit и get_bit, которая могла бы принимать массив байтов и битовое смещение в массиве, и использовать некоторую битовую перестановку, чтобы установить / получить соответствующий бит в массиве. Что-то вроде этого (на C, но, надеюсь, вы уловили идею):

// sets the n-th bit in |bytes|. num_bytes is the number of bytes in the array
// result is 0 on success, non-zero on failure (offset out-of-bounds)
int set_bit(char* bytes, unsigned long num_bytes, unsigned long offset)
{
  // make sure offset is valid
  if (offset < 0 || offset > (num_bytes<<3)-1) { return -1; }

  //set the right bit
  bytes[offset >> 3] |= (1 << (offset & 0x7));

  return 0; //success 
}

//gets the n-th bit in |bytes|. num_bytes is the number of bytes in the array
// returns (-1) on error, 0 if bit is "off", positive number if "on"
int get_bit(char* bytes, unsigned long num_bytes, unsigned long offset)
{
  // make sure offset is valid
  if (offset < 0 || offset > (num_bytes<<3)-1) { return -1; }

  //get the right bit
  return (bytes[offset >> 3] & (1 << (offset & 0x7));
}

Некоторые языки (я считаю, что Perl не уверен) разрешают побитовую арифметику над строками. Дает вам гораздо больший радиус действия. ((strlen * 8bit chars) комбинации)

Однако я бы не стал использовать одно значение для наложения более одного / типа / данных. Базовый триплет r / w / x 3-битных int, вероятно, будет верхним «практическим» пределом не из соображений экономии места, а из соображений практического развития.

(Php использует эту систему для управления своими сообщениями об ошибках, и я уже обнаружил, что это немного чрезмерно, когда вам нужно определить значения, в которых константы php не являются резидентными, и вам нужно сгенерировать целое число вручную, и честно говоря, если бы chmod не поддерживал синтаксис стиля 'ugo + rwx', я бы никогда не захотел его использовать, потому что я никогда не могу вспомнить магические числа)

В тот момент, когда вам нужно открыть таблицу констант для отладки кода, вы понимаете, что зашли слишком далеко.

Вы пометили этот вопрос как SQL, поэтому я думаю, вам нужно проконсультироваться с документацией по вашей базе данных, чтобы узнать размер целого числа. Затем вычтите один бит для знака, на всякий случай.

Редактировать: В вашем комментарии говорится, что вы используете MySQL. В документации для Числовые типы MySQL 5.0 указано, что максимальный размер NUMERIC составляет 64 или 65 цифр. Это 212 бит для 64 цифр.

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

да, тип данных mysql BIGINT - 64-битный. Мне было интересно, какой тип поля использовать, если вам нужно более 64 флагов.

nickf 07.10.2008 07:17

Microsoft SQL Server имеет интересную оптимизацию, благодаря которой он упаковывает до 8-битных столбцов в один байт в строке. В документации не упоминается верхний предел количества битовых столбцов, которые может иметь таблица. Эта оптимизация позволяет обрабатывать каждый бит как отдельный объект и позволить механизму заботиться о его сохранении, извлечении и обновлении.

David A. Gray 01.08.2015 02:26

Старый поток, но стоит упомянуть, что есть случаи, когда требуются раздутые битовые маски, например молекулярные отпечатки пальцев, которые часто генерируются как 1024-битные массивы, которые мы упаковали в 32 поля bigint (SQL Server не поддерживает UInt32). Побитовые операции работают нормально - до тех пор, пока ваша таблица не начнет расти и вы не поймете медлительность отдельных вызовов функций. Бинарный тип данных работал бы, если бы не запрет T-SQL на побитовые операторы, имеющие два бинарных операнда.

Другие вопросы по теме