Probar si varios bits están "seteados"

Iniciado por huchoko, 15 Junio 2019, 07:17 AM

0 Miembros y 1 Visitante están viendo este tema.

huchoko

Buenas, tal cual en el título, nececito probar si varios bits de una variable estan "seteados" osea valen 1 (como saben bit 0 o 1).
Puedo comprobar un solo bit con:

if (variableacomprobar & indexdelbit) {
    /* etc... */
}

Pero como lo hago para varios a la vez?
Por ejemplo, tengo una varible con dos bits que quiero comprobar a la vez:
Bits 7 y 6: quiero comprobar si el uno (bit 7) y el cero (bit 6) valen 1 y viceversa. Osea:

|15...|7|6|5|4|3|2|1|0|
       | |
       1 0
     Ó
       0 1

Espero haberme explicado bien, cualquier confusión preguntenme por aclaración. :)

@XSStringManolo

#1
Lo puedes hacer de mucha maneras.
Guardas los bit en una cadena. Te inventas otra cadena para comparar. Recorres ambas cadenas con un bucle for y las comparas.
Ejemplo:
Código (cpp) [Seleccionar]
string cadena1 = "10001011";
string cadenaParaComprobar = "11111111";

for (int i = 0; i < cadena1.size(); ++i)
{
    if (cadena1[i] == cadenaParaComprobar[i])
     {
    cout << "El bit numero " << i << " esta set" <<endl;
     }
}


Puedes usar los operadores bitwise diseñhados para eso de 200 maneras distintas para hacer lo mismo. Se suelen usar para comparar los bits, sumarlos, restarlos, desplazarlos, etc.


Pd: Te pongo ejemplos de los operadores.
Citarresultado = X & Y;
X= 00001111
Y= 00011000

El resultado será:
00001000

Citarresultado = X | Y;
X= 00001111
Y= 00011000

El resultado será:
00011111

Citarresultado = X ^ Y;
X= 00001111
Y= 00011000

El resultado será:
00010111

Citarresultado = 1 << 1;

El resultado será:
00000010
Es decir, 2 en decimal.

Citarresultado = 1 >> 1;

El resultado será:
00000000
0 en decimal. Hechó al uno fuera y no había bits para guardar su valor. Se perdió.

Eternal Idol

#2
https://en.wikipedia.org/wiki/Bitwise_operation

Supongamos que te interesa comprobar el tercer y el octavo bit. Siendo mask1 0x4 (100b = 0x4) y mask2 0x80 (10000000b = 0x80 = 128).

Código (c++) [Seleccionar]

if ( (var & mask1) && !(var & mask2) )
...
else if ( !(var & mask1) && (var & mask2) )
...


O:
Código (c++) [Seleccionar]
if ( (var & (mask1 | mask2)) == mask1)
...
else if ( (var & (mask1 | mask2)) == mask2)
...


Se puede hacer de muchas maneras, con diferente grado de optimizacion.
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

@XSStringManolo

Es de una traducción al español que estoy haciendo del libro de Apress Learn C++ for game development.

Capitulo 18: La STL. bitset.

El bitset no es exactamente un contenedor, se parece mas a un tipo de dato de STL.
No es compatible con iteradores, bucles for basados en rango o algoritmos STL.
Se utiliza para seguir valores booleanos en un set combinado. El metodo tradicional
para conseguir el mismo resultado son las flags implementadas usando operadores
bitwise y shifts.

Una de las diferencias de bitset con respecto a los contenedores de la STL es que no
necesitas especificar un tipo para el bitset.

Especializando bitset:

#include <bitset>

using namespace std;

namespace
{
   const unsigned int NUMERO_DE_BITS = 5
}

using MiBitset = bitset<NUMERO_DE_BITS>;



Diferentes constructores para bitset:

MiBitset DefaultConstructor; //Inicializa todos los bits a 0.
MiBitset UnsignedLongConstructor{0x17}; //Valor literal
MiBitset StringConstructor{ string{ "11011"} };



Trabajando con bitsets.
Un biset proporciona metodos para realizar un buen numero de operaciones
diferentes. Estos pueden dividirse entre metodos que preguntan sobre el
estado actual del bitset, y metodos usados para alterar los bits.

cout << boolalpha;

cout << "Tamanho del bitset: " << StringConstructor.size() << endl;
cout << "Numero de bits asignados: " << StringConstructor.count() << endl;

cout << "Hay algun bit asignado? " << StringConstructor.any() << endl;
cout << "Estan todos los bit asignados? "<<StringConstructor.all() << endl;
cout << "No hay bits asignados? " << StringConstructor.none() << endl;

for (unsigned int i = 0; i < StringConstructor.size(); ++i)
{
   cout << "Bit " << i << " Valor: " << StringConstructor << endl;
   cout << "Bit " << i << " test: " << stringConstructor.test(i) << endl;
}

El metodo size retorna el valor que le pasamos en la plantilla. El metodo
count retorna el numero de bit a los que le asignamos true.



Hay tres metodos para alterar los valores almacenados en bitset:

StringConstructor.set(1, false);
StringConstructor.set(1);
StringConstructor.set();

StringConstructor.reset(0);
StringConstructor.reset();

StringConstructor.flip(4);  
StringConstructor.flip();


El primer ejemplo utiliza el index de un bit y el valor a asignarle a ese bit.
El segundo utiliza solo un index y asigna 1 al bit correspondiente.
El tercero asigna 1 a todos los bits en el set.
El metodo reset hace lo mismo pero en vez de unos, asigna ceros.
El metodo flip cambia los unos por ceros y los ceros por unos. En caso de
indicarle un index, solo cambiara el bit que se encuentre en ese index.

RayR

Primero, aclarar, tú lo quieres es probar si varios bits están todos encendidos o ninguno, porque probarlos individualmente ya lo sabes hacer, ¿cierto?

La forma más simple sería (suponiendo que mascara1, mascara2, etc. contienen cada una 1 bit a probar):

if ((variable & mascara1) && (variable & mascara2) &&  ...
Pero si son muchos bits a probar quedaría una condición larguísima y tendrías demasiadas operaciones. Mejor preparar una máscara combinada y hacer algo así:

mascara = mascara1 | mascara2 | ...

// Todos on
if ( (variable & mascara) == mascara)
...
// Todos off
if (!(variable & mascara))

Loretz

#5
Si lo que necesitas es saber si está activo el bit 6 o el 7, pero no ambos a la vez, y no te importa cual de los dos, siempre que sea uno y solo uno de ellos el que esté activo, podrías hacer:

[EDITO:]
   unsigned var = 182;         // 1011 0110
   unsigned mask6 = 0x40;      // 0100 0000
   unsigned mask7 = 0x80;      // 1000 0000

   bool res = (var & mask6 || var & mask7) && !(var & mask6 && var & mask7);


En C++ puedes usar std::bitset también, que es más fácil para todos.