2010-10-29 3 views
13

Каков наилучший способ выполнения побитовых операций на vector<bool>?Побитовые операции над вектором <bool>

как я понимаю, vector<bool> - это специализация, которая использует один бит в буле. Я выбрал vector<bool> для экономии памяти. Я знаю, что есть некоторые проблемы с vector<bool>, но для моих нужд это удобно.

сейчас - что является наиболее эффективным способом приведения поразрядных операций в целые такие векторы?

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

спасибо!

+0

+1 для получения правильного ответа, задавая неправильный вопрос. – ergosys

ответ

8

Если число битов фиксируется во время компиляции, то было бы гораздо лучше использовать std::bitset

Если нет, то (т.е. число битов изменяется во время выполнения), то вы должны увидеть и может использовать boost::dynamic_bitset)

В обоих случаях очень просто выполнять все побитовые операции.

+0

+1 потому что я бы использовал эти библиотеки, если бы решил, что могу использовать зависимости для проекта, над которым я работал. –

+0

Приведенная ссылка на документацию битового набора иногда меняется и больше не действительна. Существует ссылка на текущую последнюю версию и станет недействительной: http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a00396.html – Jimbo

+0

Побитовые операторы на любом из них делают авто-векторизацию с помощью gcc и clang, делая 16 или 32 байта за раз. Они очень хорошие. https://godbolt.org/g/cnRFEG (Но 'boost :: dynamic_bitset' имеет довольно плохой' .count() ', используя байтовый-LUT, даже если доступны команды' popcnt' и AVX2 '. std: : bitset' имеет хорошую '.count()' производительность тоже.) –

4

Игнорирование название вашего вопроса, позволяет ответить на этот вопрос, вместо того, чтобы:

что лучший способ выполнить битовую операцию над вектором?

Лучший способ определить свой вектор в vector<unsigned char> (или vector<uint32_t>, или в зависимости от того другого целого типа вы выбираете), и сделать ваши битовые операции, как вы это обычно для массива целых чисел без знака. Все будет намного быстрее, и не будет скрытого механизма.

Вы можете использовать деление (или побитовые операторы, если вы используете), чтобы разрешить, с каким индексом массива вам нужно работать, и for-loops применять побитовые операции, превышающие один элемент.

Вот связанный с этим вопрос: Bit twiddling a lot of bits in C

Вы в основном будете делать эту же операцию, если и когда вы решили обернуть vector<unsigned some-int-type> со своими собственными операторами.

+0

, так что, если я все еще хочу получить доступ к своим логическим значениям напрямую, мне действительно нужно инкапсулировать вектор и сделать вектор механики сам, просто дополнительно предоставляя функциональность для побитовых операций? – Mat

+0

@Mat: У вас нет * иметь * что-то делать, но чтобы получить лучшую производительность, я предлагаю сделать то, что вы только что описали. Оберните все это в классе и внесите в него перегруженные операторы. Тогда вы можете оптимизировать свое содержание. Это действительно не очень сложный код для реализации, и дает вам правильный баланс абстракции и производительности. –

+0

На самом деле, я просто хотел узнать, не существует ли эта функциональность, возможно, уже существует? потому что для меня кажется логичным, что это то, что вы хотите делать с битрейтерами – Mat

3

Я прочитал оба этих ответа, но просто хотел получить быстрое решение и реализовал что-то ужасное.

Вы можете заставить побитовые операторы работать на vector<bool>, но код должен быть специализированным для реализации стандартной библиотеки C++ или вернуться к медленной форме. Вот мой operator| для GNU libstdC++ - v3:

std::vector<bool> operator|(std::vector<bool> A, const std::vector<bool>& B) 
{ 
    if (A.size() != B.size()) 
     throw std::invalid_argument("differently sized bitwise operands"); 

    std::vector<bool>::iterator itA = A.begin(); 
    std::vector<bool>::const_iterator itB = B.begin(); 

    // c++ implementation-specific 
    while (itA < A.end()) 
     *(itA._M_p ++) |= *(itB._M_p ++); // word-at-a-time bitwise operation 

    return A; 
} 

Это, конечно, очень плохо. Кто-то обновляет GCC, новая версия хранит вещи по-другому, и ваш код прерывается без видимых причин.

+0

К сожалению, это не авто-векторизация gcc или clang для x86-64, с '-O3 -march = haswell'. https://godbolt.org/g/eJnfKp. Он должен использовать AVX2 для 'vpor' 32 байта за раз, а не только по 8 за один раз со скаляром' или'. Boost 'dynamic_bitset <>' делает auto-vectorize для 'a & b'. Но, к сожалению, функция '.count()' boost не очень эффективна. (Но гораздо лучше, чем 'std :: count' на' vector ', если вы не используете' clang -stdlib = libC++ ', и в этом случае это векторный рисунок с помощью AVX2.) –

+0

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

+0

@PeterCordes - 'clang' может быть [уговорен] (https://godbolt.org/g/UJvAez) в создании некоторого довольно хорошего для бит-ops (' и 'в этом примере) с использованием временного массива в стеке. Хранение стека, а затем перезагрузка на самом деле не является ужасным способом получить 4 значения из 'ymm' в место, которое оно может использовать' popcnt'. «Mov r9, rcx; или r9, 8' ops, чередующиеся с векторизованным и немного глупые и могут стоить немного пропускной способности (почему они просто не используют смещение в режимах адресации или, по крайней мере, делают это с помощью одного «add»?). – BeeOnRope

-1

This one также должен работать.

std::vector<bool> v3(v1.size()); 
std::transform(v1.begin(), v1.end(), 
       v2.begin(), v3.begin(), std::logical_and<bool>()); 
+0

Это будет невероятно неэффективно, потому что каждый бит должен быть извлечен из его слова, затем преобразован, а затем вставлен обратно в слово. Решения, которые работают по слову за раз, будут намного эффективнее. – Joel

+0

@Joel: Стандартные библиотеки [могут и должны специализировать свои шаблоны алгоритмов 'std' для' vector '] (https://isocpp.org/blog/2012/11/on-vectorbool). libC++ делает для некоторых вещей (например, 'std :: count' on' vector 'авто-векторизациями очень хорошего кода AVX2). Но в этом случае clang и gcc с libC++ и libstdC++ оба делают * страшный * код, зацикливая бит за раз и даже не делая И эффективно. (Тестирование бит отдельно на каждом входе и использование условных ветвей! Https://godbolt.org/g/4MDd8v) (Даже если вы используете 'std :: bit_and' вместо' logical_and'). –

+0

В любом случае, этот ответ не является технически плохим, он просто предоставляет MASSIVE пропущенные оптимизации компиляторами и стандартными библиотечными редакторами. Это означает, что на практике вы не должны его использовать. –

 Смежные вопросы

  • Нет связанных вопросов^_^