Como executar uma operação bit a bit em números de ponto flutuante

Eu tentei isso:

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

Eu recebo um erro do compilador dizendo que o operando de & não pode ser do tipo float.

Quando eu faço:

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

Eu recebo o programa em execução. A única coisa é que a operação bit a bit é feita na representação inteira do número obtido após o arredondamento.

O seguinte também não é permitido.

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

Eu não entendo porque int pode ser lançado para void* mas não float .

Eu estou fazendo isso para resolver o problema descrito na pergunta Stack Overflow Como resolver equações lineares usando um algoritmo genético? .

No nível da linguagem, não existe “operação bit a bit em números de ponto flutuante”. Operações bit a bit em C / C ++ funcionam na representação de valor de um número. E a representação de valor de números de ponto flutuante não é definida em C / C ++. Os números de ponto flutuante não possuem bits no nível de representação de valor, e é por isso que você não pode aplicar operações bit a bit a eles.

Tudo o que você pode fazer é analisar o conteúdo de bit da memory bruta ocupada pelo número de ponto flutuante. Para isso você precisa usar uma união como sugerido abaixo ou (equivalentemente, e somente em C ++) reinterpretar o object de ponto flutuante como uma matriz de objects unsigned char , como em

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

E por favor, não tente reinterpretar um object float como um object int , como outras respostas sugerem. Isso não faz muito sentido, isso é ilegal, e não é garantido que funcione em compiladores que seguem regras de otimização de alias restritas. A única maneira legal de inspecionar o conteúdo da memory em C ++ é reinterpretando-o como uma matriz de [signed/unsigned] char .

Observe também que, tecnicamente, não é garantido que a representação de ponto flutuante em seu sistema seja IEEE754 (embora na prática seja a menos que você permita explicitamente que não seja, e somente com respeito a -0.0, ± infinity e NaN).

Se você está tentando mudar os bits na representação de ponto flutuante, você poderia fazer algo como isto:

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

Como observa AndreyT, acessar uma união como essa invoca um comportamento indefinido, e o compilador pode criar armas e estrangulá-lo. Faça o que ele sugere.

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

Dê uma olhada no seguinte. Inspirado pela raiz quadrada 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; } 

@mobrule:

Melhor:

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

Para estes valores int provavelmente estará ok, mas geralmente, você deve usar ints não assinados para bit shift para evitar os efeitos de mudanças aritméticas. E o uint32_t funcionará mesmo em sistemas cujos ints não sejam 32 bits.

A implementação Python em operações bitwise de ponto flutuante (receita Python) de operações bit a bit de ponto flutuante funciona representando números em binário que se estendem infinitamente para a esquerda e para a direita a partir do ponto fracionário. Como os números de ponto flutuante têm um zero com sinal na maioria das arquiteturas, ele usa o complemento para representar números negativos (bem, na verdade, ele apenas finge e usa alguns truques para obter a aparência).

Tenho certeza de que ele pode ser adaptado para funcionar em C ++, mas é preciso ter cuidado para não permitir que os deslocamentos corretos estourem ao equalizar os expoentes.

Os operadores bit a bit NÃO devem ser usados ​​em floats, pois os floats são específicos do hardware, independentemente da similaridade em qualquer hardware que você possa ter. Qual projeto / trabalho você quer arriscar em “bem funcionou na minha máquina”? Em vez disso, para C ++, você pode obter uma “sensação” semelhante para os operadores de deslocamento de bits sobrecarregando o operador de stream em um wrapper de “object” para um float:

 // Simple object wrapper for float type as templates want classs. 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; } 

Você terá um restante, que pode ser descartado com base na implementação desejada.

 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) 

Isso é semelhante à resposta de Justin, exceto que ele apenas cria uma visão dos bits nos mesmos registros de a . Então, quando você manipula *b , o valor de a é alterado de acordo.

FWIW, há um caso real de uso para operações bit-wise em ponto flutuante (acabei de executá-lo recentemente) – shaders escritos para GPUs que suportam apenas versões mais antigas do GLSL (1.2 e anteriores não tinham suporte para operadores bit-wise) e onde haveria perda de precisão se os flutuadores fossem convertidos em ints.

As operações bit a bit podem ser implementadas em números de ponto flutuante usando verificações de restos (modulo) e de desigualdade. Por exemplo:

 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 

O acima assume que A está entre [0..1] e que existe apenas um “bit” na máscara para verificar, mas pode ser generalizado para casos mais complexos.

Esta idéia é baseada em algumas das informações encontradas em is-it-possible-to-implementation-bitwise-operadores-usando-inteiros-aritméticos

Se não houver nem mesmo uma function mod integrada, isso também pode ser implementado com bastante facilidade. Por exemplo:

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