2010-10-29 15 views
13

¿cuál es la mejor forma de realizar operaciones bit a bit en vector<bool>?operaciones bit a bit en el vector <bool>

según tengo entendido, vector<bool> es una especialización que utiliza un bit por booleano. Elegí vector<bool> por razones de ahorro de memoria. Sé que hay algunos problemas con vector<bool> pero para mis necesidades es apropiado.

ahora - ¿Cuál es la forma más efectiva de aplicar operaciones bit a bit a vectores completos?

si lo hago en un bucle for y lea cada bool y lo guardo de nuevo, de la manera que lo entiendo se realizan muchas más operaciones dentro para acceder a los valores reales.

gracias!

+0

+1 para obtener la respuesta correcta haciendo la pregunta incorrecta. – ergosys

Respuesta

8

Si el número de bits se fijan en tiempo de compilación, que sería mucho mejor usar std::bitset

Si no es así, (es decir, número de bits variable en tiempo de ejecución), entonces usted debe ver y se puede utilizar boost::dynamic_bitset)

En ambos, es extremadamente fácil realizar todas las operaciones de bit a bit.

+0

+1 porque usaría estas bibliotecas si decidiera tomar las dependencias del proyecto en el que estaba trabajando. –

+0

El enlace provisto a la documentación del conjunto de bits cambia ocasionalmente y ya no es válido. Hay un enlace a la última versión actual y se volverá inválido: http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-api-4.5/a00396.html – Jimbo

+0

Operaciones a nivel de bit en cualquiera de ellas auto-vectorize con gcc y clang, haciendo 16 o 32 bytes a la vez. Ellos son muy buenos. https://godbolt.org/g/cnRFEG (Pero 'boost :: dynamic_bitset' tiene un' .count() 'bastante pobre, usando un byte-LUT incluso cuando el hardware' popcnt' y las instrucciones de AVX2 están disponibles. 'std: : bitset' tiene un buen rendimiento '.count()', también.) –

4

Ignorando el título de tu pregunta, deja de responder a esta pregunta , en su lugar:

¿cuál es la mejor manera de realizar operaciones bit a bit en vectores?

La mejor manera es definir su vector como vector<unsigned char> (o vector<uint32_t>, o cualquier otro tipo entero a elegir), y hacer sus operaciones bit a bit cómo lo haría normalmente para una matriz de enteros sin signo. Las cosas serán mucho más rápidas de esta manera, y no habrá ningún mecanismo oculto.

Puede usar la división (o operadores bit a bit, si es hábil) para resolver qué índice de matriz necesita operar, y for-loops para aplicar operaciones bit a bit mayores que un solo elemento.

Aquí hay una pregunta relacionada: Bit twiddling a lot of bits in C

Usted básicamente estar haciendo estas mismas operaciones, siempre y cuando se decida a envolver vector<unsigned some-int-type> con sus propios operadores.

+0

así que si todavía quiero la posibilidad de acceder directamente a mis valores booleanos, de hecho tengo que encapsular el vector y hacer el vector Mecánico, solo adicionalmente también brindando funcionalidad para operaciones bit a bit. – Mat

+0

@Mat: No * tiene * que hacer nada, pero para obtener el mejor rendimiento, sugiero hacer lo que acaba de describir. Envuelva todo en una clase e implemente operadores sobrecargados. Entonces puedes optimizar al contenido de tu corazón. Realmente no es un código muy complicado de implementar, y le da el equilibrio correcto de abstracción y rendimiento. –

+0

en realidad solo quería saber con esto si esta funcionalidad tal vez ya no existe? porque me parece lógico que esto sea algo que quieras hacer con bitvectors – Mat

3

He leído ambas respuestas, pero solo quería una solución rápida, e implementé algo horrible.

Puede hacer que los operadores bit a bit trabajen en vector<bool>, pero el código tiene que estar especializado para la implementación de la biblioteca estándar de C++ o volver a la forma lenta. Aquí es mi operator| para 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; 
} 

Esto es, por supuesto, bastante malo. Alguien actualiza GCC, la nueva versión almacena las cosas de manera diferente y tu código se rompe sin ningún motivo aparente.

+0

Desafortunadamente, no se auto-vectoriza con gcc o clang para x86-64, con '-O3 -march = haswell'. https://godbolt.org/g/eJnfKp. Debería usar AVX2 a 'vpor' 32 bytes a la vez, en vez de solo 8 a la vez con escalar' o'. El 'dynamic_bitset <>' de Boost se auto-vectoriza para 'a & b'. Pero desafortunadamente la función '.count()' de boost no es muy eficiente. (Pero mucho mejor que 'std :: count' on' vector ', a menos que use' clang -stdlib = libC++ 'en cuyo caso eso se vectoriza con AVX2.) –

+0

De todos modos, no he encontrado una manera de obtener un buen código para una cuenta del resultado de una operación booleana entre dos vectores de bits de tamaño dinámico, además de vectorizarlo manualmente, por supuesto. –

+0

@PeterCordes - 'clang' puede ser [persuadido] (https://godbolt.org/g/UJvAez) para producir algunos bastante buenos para bit-ops (' y' en este ejemplo) usando una matriz temporal en la pila. Almacenar en la pila y luego volver a cargar no es realmente una forma terrible de obtener 4 valores de un 'ymm' en un lugar que pueda ser utilizado por' popcnt'. El 'mov r9, rcx; o r9, 8' ops intercalados con el vectorizado y es un poco tonto y puede costar un poco de rendimiento (¿por qué no usaron simplemente un desplazamiento en los modos de direccionamiento, o al menos lo hicieron con un solo 'add'?) – BeeOnRope

-1

This one debería funcionar también.

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

Esto será increíblemente ineficiente porque cada bit debe extraerse de su palabra, luego transformarse y luego insertarse de nuevo en la palabra. Las soluciones que operan en una palabra a la vez serán mucho más eficientes. – Joel

+0

@Joel: bibliotecas estándar [pueden y deben especializar sus plantillas de algoritmo 'std' para' vector '] (https://isocpp.org/blog/2012/11/on-vectorbool). libC++ lo hace para algunas cosas (por ejemplo 'std :: count' on' vector 'auto-vectorizes a muy buen código AVX2). Pero en este caso, clang y gcc con libC++ y libstdC++ ambos hacen código * terrible *, haciendo bucles un poco a la vez y sin hacer el AND de manera eficiente. (¡Probar el bit por separado en cada entrada, y usar las ramas condicionales! Https://godbolt.org/g/4MDd8v) (Incluso si usa 'std :: bit_and' en lugar de' logical_and'). –

+0

De todos modos, esta respuesta no es técnicamente mala, solo expone MASSIVE optimizaciones perdidas por compiladores y escritores de bibliotecas estándar. Lo que significa que en la práctica no deberías usarlo todavía. –

Cuestiones relacionadas