views:

1098

answers:

5

i tried this:

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

i get a compiler error saying that operand to & cannot be of type float.

when i do:

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

i get the program running. only thing is that the bitwise operation is done on the integer representation of the number obtained after rounding off.

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

is also not allowed. i don't understand why int can be cast to void* but not float.

i am doing this to solve this problem.

+8  A: 
float a = 1.4123;
unsigned int* inta = reinterpret_cast<unsigned int*>(&a);
*inta = *inta & (1 << 3);
Chap
Aaron
Cecil Has a Name
@Cecil Has a Name: using c++ casts
Chap
C++ casts (XXX_cast<>) are preferred because 1) they are easier to search for, and 2) reinterpret_cast makes it clear that you are doing something system dependent, and potentially dangerous.
KeithB
You should isolate this operation in a class for system specific operations since it is heavily dependent on the target system
Chap
+8  A: 

If you are trying to change the bits in the floating-point representation, you could do something like this:

union fp_bit_twiddler {
    float f;
    int i;
} q;
q.f = a;
q.i &= (1 << 3);
a = q.f;
mobrule
Technically, this is undefined behavior. You can only access the member of a union that you last wrote to.
KeithB
Is it good practice to include a compile-time assert that the `float` and `int` have the same size?
jleedev
@KeithB: really, is it compiler dependent. does the standard not say, the bitwise representation would be the same.
iamrohitbanga
Good points about making sure `int` and `float` are the same size. Tim Schaeffer's solution is more portable.
mobrule
@mobrule should i change my answer
iamrohitbanga
any how i found that swapping random bits in the actual floating point representation does not lead to good chromosomes as already mentioned in the post quoted in my question. nevertheless, this union thing didn't strike me. so thanks.
iamrohitbanga
+1  A: 

@mobrule:

Better:

#include <stdint.h>
...
union fp_bit_twiddler {
    float f;
    uint32_t u;
} q;

/* mutatis mutandis ... */

For these values int will likely be ok, but generally, you should use unsigned ints for bit shifting to avoid the effects of arithmetic shifts. And the uint32_t will work even on systems whose ints are not 32 bits.

Tim Schaeffer
Of course, this still won't work for systems whose floats are not 32 bits.
AndreyT
Floating point numbers nowadays usually follow the IEEE standards, so floats are usually 32 bits and doubles usually 64. There have got to be exceptions out there, but I haven't encountered them. However, assert(sizeof(float)==sizeof(uint32_t)); is easy to write.
David Thornley
+9  A: 

At the language level, there's no such thing as "bitwise operation on floating-point numbers". Bitwise operations in C++ work on value-representation of a number. And the value-representation of floating point numbers is not defined in C++. Floating point numbers don't have bits at the level of value-representation, which is why you can't apply bitwise operations to them.

All you can do is analyze the bit content of the raw memory occupied by the floating-point number. For that you need to reinterpret the floating-point object as an array of unsigned char objects, as in

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

And please, don't try to reinterpret a float object as an int object, as other answers suggest. That doesn't make much sense, that is illegal, and that is not guaranteed to work in compilers that follow strict-aliasing rules in optimization. The only legal way to inspect memory content in C++ is by reinterpreting it as an array of [signed/unsigned] char.

AndreyT
if you get more votes, i'll mark your answer as correct.
iamrohitbanga
Votes :) C and C++ languages are like math. The correctness of a formal statement is defined by hard facts and hard proofs, not by consensus of the majority. Majority (votes) doesn't matter.
AndreyT
@Chap: You are confused. The diffewrence with `int` is *huge*. The size of `char` in machine bytes is system dependent, but the size of `char` at the language level is not. Size of `char` is always 1 at the language level, meaning that every other type's size is divisible by size of `char`. Additionally, `unsigned char` has no padding bits in it and all combinations of bits are valid. You can't say that about `int`. This all is why every object in C++ can be reinterpreted as an array of `char`s, but can't be reinterpreted as an [array of] `int`.
AndreyT
@Chap: What you are saying about system-dependent representation of `float` is true, but that's exactly the point of my answer. As I said, you can only inspect *raw memory* representation of a `float` object, which is synonymous with it being "system-dependent". The point is that if the OP *wants/needs* to inspect the raw memory representation of `float` for some reason, then that the way to do it.
AndreyT
The IEEE has some floating point standards that are making floating-point numbers much more uniform. They still don't lend themselves to casual bitwise operations.
David Thornley
@Chap: There's a difference between doing something *implementation-defined* in C and something *undefined* in C. When I need to do something implementation-defined I would still prefer to: 1) keep system-dependency to a minimum, 2) if possible, avoid relying on undefined behavior. This is what makes `unsigned char` array solution better than an `int` solution.
AndreyT
@Chap: In short, even if you have to do something system-dependent, it is still not an excuse to invoke undefined behavior. Unless you have a *very very very* good reason, relying on UB is best avoided. Especially if there's an obvious alternative solution without any UB.
AndreyT
+2  A: 

Have a look at the following. Inspired by fast inverse square root:

#include <iostream>
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; 
}
Justin
i think this is part of linux kernel code
iamrohitbanga