Класс bitset
Таблица 4.4. Операции с классом bitset
Операция | Значение | Использование | |||
test(pos) | Бит pos
равен 1? | a.test(4) | |||
any() | Хотя бы один бит равен 1? | a.any() | |||
none() | Ни один бит не равен 1? | a.none() | |||
count() | Количество битов, равных 1 | a.count() | |||
size() | Общее количество битов | a.size() | |||
[pos] | Доступ к биту pos | a[4] | |||
flip() | Изменить значения всех | a.flip() | |||
flip(pos) | Изменить значение бита pos | a.flip(4) | |||
set() | Выставить все биты в 1 | a.set() | |||
set(pos) | Выставить бит pos в 1 | a.set(4) | |||
reset() | Выставить все биты в 0 | a.reset() | |||
reset(pos) | Выставить бит pos в 0 | a.reset(4) |
Как мы уже говорили, необходимость создавать сложные выражения для манипуляции битовыми векторами затрудняет использование встроенных типов данных. Класс bitset
упрощает работу с битовым вектором. Вот какое выражение нам приходилось писать в предыдущем разделе для того, чтобы “взвести” 27-й бит:
quiz1 |= 1<<27;
При использовании bitset то же самое мы можем сделать двумя способами:
quiz1[27] = 1;
или
quiz1.set(27);
(В нашем примере мы не используем нулевой бит, чтобы сохранить “естественную” нумерацию. На самом деле, нумерация битов начинается с 0.)
Для использования класса bitset
необходимо включить заголовочный файл:
#include <bitset>
Объект типа bitset
может быть объявлен тремя способами. В определении по умолчанию мы просто указываем размер битового вектора:
bitset<32> bitvec;
Это определение задает объект bitset, содержащий 32 бита с номерами от 0 до 31. Все биты инициализируются нулем. С помощью функции any()
можно проверить, есть ли в векторе единичные биты. Эта функция возвращает true, если хотя бы один бит отличен от нуля. Например:
bool is_set = bitvec.any();
Переменная is_set
получит значение false, так как объект bitset по умолчанию инициализируется нулями. Парная функция none()
возвращает true, если все биты равны нулю:
bool is_not_set = bitvec.none();
Изменить значение отдельного бита можно двумя способами: воспользовавшись функциями set() и reset() или индексом. Так, следующий цикл выставляет в 1 каждый четный бит:
for ( int index=0; index<32; ++index ) if ( index % 2 == 0 ) |
Аналогично существует два способа проверки значений каждого бита – с помощью функции test() и с помощью индекса. Функция () возвращает true, если соответствующий бит равен 1, и false в противном случае. Например:
if ( bitvec.test( 0 )) |
Значения битов с помощью индекса проверяются таким образом:
cout << "bitvec: включенные биты:\n\t"; for ( int index = 0; index < 32; ++-index ) if ( bitvec[ index ] ) cout << index << " "; |
Следующая пара операторов демонстрирует сброс первого бита двумя способами:
bitvec.reset(0); |
Функции set() и reset()
могут применяться ко всему битовому вектору в целом. В этом случае они должны быть вызваны без параметра. Например:
// сброс всех битов bitvec.reset(); if (bitvec.none() != true) // что-то не сработало // установить в 1 все биты вектора bitvec if ( bitvec.any() != true ) |
Функция flip()
меняет значение отдельного бита или всего битового вектора:
bitvec.f1ip( 0 ); // меняет значение первого бита bitvec[0].flip(); // тоже меняет значение первого бита |
Существуют еще два способа определить объект типа bitset. Оба они дают возможность проинициализировать объект определенным набором нулей и единиц. Первый способ – явно задать целое беззнаковое число как аргумент конструктору. Начальные N позиций битового вектора получат значения соответствующих двоичных разрядов аргумента. Например:
bitset< 32 > bitvec2( Oxffff );
инициализирует bitvec2
следующим набором значений:
00000000000000001111111111111111
В результате определения
bitset< 32 > bitvec3( 012 );
у bitvec3
окажутся ненулевыми биты на местах 1 и 3:
00000000000000000000000000001010
В качестве аргумента конструктору может быть передано и строковое значение, состоящее из нулей и единиц. Например, следующее определение инициализирует bitvec4 тем же набором значений, что и bitvec3:
// эквивалентно bitvec3 string bitva1( "1010" ); |
Можно также указать диапазон символов строки, выступающих как начальные значения для битового вектора. Например:
// подстрока с шестой позиции длиной 4: 1010 string bitval ( "1111110101100011010101" ); |
Мы получаем то же значение, что и для bitvec3 и bitvec4. Если опустить третий параметр, подстрока берется до конца исходной строки:
// подстрока с шестой позиции до конца строки: 1010101 string bitva1( "1111110101100011010101" ); |
Класс bitset
предоставляет две функции-члена для преобразования объекта bitset в другой тип. Для трансформации в строку, состоящую из символов нулей и единиц, служит функция to_string():
string bitva1( bitvec3.to_string() );
Вторая функция, to_long(), преобразует битовый вектор в его целочисленное представление в виде unsigned long, если, конечно, оно помещается в unsigned long. Это видоизменение особенно полезно, если мы хотим передать битовый вектор функции на С или С++, не пользующейся стандартной библиотекой.
К объектам типа bitset
можно применять побитовые операции. Например:
bitset<32> bitvec7 = bitvec2 & bitvec3;
Объект bitvec7
инициализируется результатом побитового И двух битовых векторов bitvec2 и bitvec3.
bitset<32> bitvec8 = bitvec2 | bitvec3;
Здесь bitvec8
инициализируется результатом побитового ИЛИ векторов bitvec2 и bitvec3. Точно так же поддерживаются и составные операции присваивания и сдвига.
Упражнение 4.15
Допущены ли ошибки в приведенных определениях битовых векторов?
(a) bitset<64> bitvec(32);
(b) bitset<32> bv( 1010101 );
(c) string bstr; cin >> bstr; bitset<8>bv( bstr );
(d) bitset<32> bv; bitset<16> bvl6( bv );
Упражнение 4.16
Допущены ли ошибки в следующих операциях с битовыми векторами?
extern void bitstring(const char*); bool bit_on (unsigned long, int); bitset<32> bitvec; (a) bitsting( bitvec.to_string().c_str() ); (b) if ( bit_on( bitvec.to_1ong(), 64 )) ... |
Упражнение 4.17
Дана последовательность: 1,2,3,5,8,13,21. Каким образом можно инициализировать объект bitset<32> для ее представления? Как присвоить значения для представления этой последовательности пустому битовому вектору? Напишите вариант инициализации и вариант с присваиванием значения каждому биту.