Cómo realizar una operación bit a bit en números de coma flotante

Intenté esto:

float a = 1.4123; a = a & (1 << 3); 

Aparece un error del comstackdor que dice que el operando de & no puede ser de tipo float.

Cuando lo hago:

 float a = 1.4123; a = (int)a & (1 << 3); 

Me sale el progtwig en ejecución. Lo único es que la operación bit a bit se realiza en la representación entera del número obtenido después del redondeo.

Lo siguiente tampoco está permitido.

 float a = 1.4123; a = (void*)a & (1 << 3); 

No entiendo por qué int se puede convertir en void* pero no float .

Estoy haciendo esto para resolver el problema descrito en Stack Overflow question. ¿Cómo resolver ecuaciones lineales usando un algoritmo genético? .

En el nivel de idioma, no hay tal cosa como “operación bit a bit en números de coma flotante”. Las operaciones bit a bit en C / C ++ funcionan en la representación de valores de un número. Y la representación de valores de los números de coma flotante no está definida en C / C ++. Los números de punto flotantes no tienen bits en el nivel de representación de valores, por lo que no puede aplicarles operaciones bit a bit.

Todo lo que puede hacer es analizar el contenido del bit de la memoria en bruto ocupada por el número de coma flotante. Para eso, necesita usar una unión como se sugiere a continuación o (de manera equivalente, y solo en C ++) reinterpretar el objeto de punto flotante como una matriz de objetos unsigned char , como en

 float f = 5; unsigned char *c = reinterpret_cast(&f); // inspect memory from c[0] to c[sizeof f - 1] 

Y por favor, no intente reinterpretar un objeto float como un objeto int , como sugieren otras respuestas. Eso no tiene mucho sentido, eso es ilegal y no está garantizado que funcione en comstackdores que sigan estrictas reglas de alias en optimización. La única forma legal de inspeccionar el contenido de la memoria en C ++ es reinterpretándolo como una matriz de caracteres [signed/unsigned] char .

También tenga en cuenta que técnicamente no se garantiza que la representación de coma flotante en su sistema sea IEEE754 (aunque en la práctica lo es a menos que permita explícitamente que no lo sea, y solo con respecto a -0.0, ± infinito y NaN).

Si intenta cambiar los bits en la representación de coma flotante, podría hacer algo como esto:

 union fp_bit_twiddler { float f; int i; } q; qf = a; qi &= (1 << 3); a = qf; 

Como señala AndreyT, acceder a un sindicato como este invoca un comportamiento indefinido, y el comstackdor podría armarse de arms y estrangularlo. Haz lo que él sugiera en su lugar.

 float a = 1.4123; unsigned int* inta = reinterpret_cast(&a); *inta = *inta & (1 << 3); 

Eche un vistazo a lo siguiente. Inspirado por la raíz cuadrada inversa rápida:

 #include  using namespace std; int main() { float x, td = 2.0; int ti = *(int*) &td; cout << "Cast int: " << ti << endl; ti = ti>>4; x = *(float*) &ti; cout << "Recast float: " << x << endl; return 0; } 

@ley de la calle:

Mejor:

 #include  ... union fp_bit_twiddler { float f; uint32_t u; } q; /* mutatis mutandis ... */ 

Para estos valores int probablemente estará bien, pero en general, debe usar ints sin signo para el cambio de bit para evitar los efectos de los cambios aritméticos. Y el uint32_t funcionará incluso en sistemas cuyos ints no sean de 32 bits.

La implementación de Python en operaciones a nivel de bit de coma flotante (receta de Python) de operaciones a nivel de coma flotante funciona representando números en binario que se extiende infinitamente tanto a la izquierda como a la derecha desde el punto fraccionario. Debido a que los números de coma flotante tienen un cero firmado en la mayoría de las architectures, usa el complemento de uno para representar números negativos (bueno, en realidad solo pretende hacerlo y usa algunos trucos para lograr la apariencia).

Estoy seguro de que se puede adaptar para trabajar en C ++, pero se debe tener cuidado para no dejar que los cambios a la derecha se desborden al ecualizar los exponentes.

Los operadores bit a bit NO se deben usar en flotadores, ya que los flotadores son específicos del hardware, independientemente de la similitud en el hardware que tengas. ¿A qué proyecto / trabajo quiere arriesgarse con “bueno, funcionó en mi máquina”? En cambio, para C ++, puede obtener una “sensación” similar para los operadores de cambio de bit al sobrecargar el operador de flujo en un contenedor de “objeto” para un flotante:

 // Simple object wrapper for float type as templates want classes. class Float { float m_f; public: Float( const float & f ) : m_f( f ) { } operator float() const { return m_f; } }; float operator>>( const Float & left, int right ) { float temp = left; for( right; right > 0; --right ) { temp /= 2.0f; } return temp; } float operator<<( const Float & left, int right ) { float temp = left; for( right; right > 0; --right ) { temp *= 2.0f; } return temp; } int main( int argc, char ** argv ) { int a1 = 40 >> 2; int a2 = 40 << 2; int a3 = 13 >> 2; int a4 = 256 >> 2; int a5 = 255 >> 2; float f1 = Float( 40.0f ) >> 2; float f2 = Float( 40.0f ) << 2; float f3 = Float( 13.0f ) >> 2; float f4 = Float( 256.0f ) >> 2; float f5 = Float( 255.0f ) >> 2; } 

Tendrá un rest, que puede tirar según su implementación deseada.

 float a = 1.4123; int *b = (int *)&a; *b = *b & (1 << 3); // a is now the IEEE floating-point value caused by the manipulation of *b // equals 1.121039e-44 (tested on my system) 

Esto es similar a la respuesta de Justin, excepto que solo crea una vista de los bits en los mismos registros que a . Entonces cuando manipulas *b , el valor de a cambia en consecuencia.

FWIW, hay un caso de uso real para operaciones bit a bit en coma flotante (me acabo de encontrar recientemente) sombreadores escritos para GPU que solo admiten versiones anteriores de GLSL (1.2 y anteriores no tenían soporte para operadores de bits) , y donde habría pérdida de precisión si los flotadores se convirtieran en ints.

Las operaciones de bits se pueden implementar en números de punto flotante utilizando residuos (módulo) y verificaciones de desigualdad. Por ejemplo:

 float A = 0.625; //value to check; ie, 160/256 float mask = 0.25; //bit to check; ie, 1/4 bool result = (mod(A, 2.0 * mask) >= mask); //non-zero if bit 0.25 is on in A 

Lo anterior supone que A está entre [0..1) y que solo hay un “bit” en la máscara para verificar, pero podría generalizarse para casos más complejos.

Esta idea se basa en parte de la información que se encuentra en is-it-possible-to-implementation-bitwise-operators-using-integer-arithmetic

Si ni siquiera hay una función de mod incorporada, eso también se puede implementar con bastante facilidad. Por ejemplo:

 float mod(float num, float den) { return num - den * floor(num / den); }