Класс 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 )
bitvec[ index ] = 1;
Аналогично существует два способа проверки значений каждого бита– с помощью функции test() и с помощью индекса. Функция () возвращает true, если соответствующий бит равен 1, и false в противном случае. Например:
if ( bitvec.test( 0 ))
// присваивание bitvec[0]=1 сработало!;
Значения битов с помощью индекса проверяются таким образом:
cout << "bitvec: включенные биты:\n\t";
for ( int index = 0; index < 32; ++-index )
if ( bitvec[ index ] )
cout << index << " ";
cout << endl;
Следующая пара операторов демонстрирует сброс первого бита двумя способами:
bitvec.reset(0);
bitvec[0] = 0;
Функции set() и reset() могут применяться ко всему битовому вектору в целом. В этом случае они должны быть вызваны без параметра. Например:
// сброс всех битов
bitvec.reset();
if (bitvec.none() != true)
// что-то не сработало
// установить в 1 все биты вектора bitvec
if ( bitvec.any() != true )
// что-то опять не сработало
Функция flip() меняет значение отдельного бита или всего битового вектора:
bitvec.f1ip( 0 ); // меняет значение первого бита
bitvec[0].flip(); // тоже меняет значение первого бита
bitvec.flip(); // меняет значения всех битов
Существуют еще два способа определить объект типа bitset. Оба они дают возможность проинициализировать объект определенным набором нулей и единиц. Первый способ – явно задать целое беззнаковое число как аргумент конструктору. Начальные N позиций битового вектора получат значения соответствующих двоичных разрядов аргумента. Например:
bitset< 32 > bitvec2( Oxffff );
инициализирует bitvec2 следующим набором значений:
00000000000000001111111111111111
В результате определения
bitset< 32 > bitvec3( 012 );
у bitvec3 окажутся ненулевыми биты на местах 1 и 3:
00000000000000000000000000001010
В качестве аргумента конструктору может быть передано и строковое значение, состоящее из нулей и единиц. Например, следующее определение инициализирует bitvec4 тем же набором значений, что и bitvec3:
// эквивалентно bitvec3
string bitva1( "1010" );
bitset< 32 > bitvec4( bitval );
Можно также указать диапазон символов строки, выступающих как начальные значения для битового вектора. Например:
// подстрока с шестой позиции длиной 4: 1010
string bitval ( "1111110101100011010101" );
bitset< 32 > bitvec5( bitval, 6, 4 );
Мы получаем то же значение, что и для bitvec3 и bitvec4. Если опустить третий параметр, подстрока берется до конца исходной строки:
// подстрока с шестой позиции до конца строки: 1010101
string bitva1( "1111110101100011010101" );
bitset< 32 > bitvec6( bitval, 6 );
Класс 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 )) ...
(c) bitvec.f1ip( bitvec.count() );
Упражнение 4.17
Дана последовательность: 1,2,3,5,8,13,21. Каким образом можно инициализировать объект bitset<32> для ее представления? Как присвоить значения для представления этой последовательности пустому битовому вектору? Напишите вариант инициализации и вариант с присваиванием значения каждому биту.