1

32 bits are represented in binary using the IEEE format. So how can I extract those bits? Bitwise operations like & and | do not work on them! what i basically want to do is extract the LSB from 32 bit float images in opencv thanx in advance!

shiladitya
  • 2,290
  • 1
  • 23
  • 36
  • possible duplicate of [Bits in C, how do I access the underlying bits in a C float?](http://stackoverflow.com/questions/9401726/bits-in-c-how-do-i-access-the-underlying-bits-in-a-c-float) – Steve Jessop Jun 21 '12 at 11:05

4 Answers4

4

You can use a union to pull values out safely (demo):

union fi_t
{
    unsigned int i;
    float f;
};

fi_t fi;
fi.f = 1.5;
unsigned int i = fi.i;

(just never typecast, this will invoke dreaded ftol, which may use SSE2 to convert to integer form, or FISTP, which won't yield the IEEE bits you are after)

zero323
  • 322,348
  • 103
  • 959
  • 935
Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • 2
    I would recommend making the union volatile for added safety, given that this union technique has been on shaky grounds with respect to the C standard(s) historically (see also the comment from Stephen Canon below). In practice, the "volatile union" approach has not failed me for 20+ years across diverse platforms and toolchains. – njuffa Jun 21 '12 at 14:24
  • @njuffa: I've never actually though of making it `volatile`, I generally just use it as is, cause Quake used this same method, and Quake seems to work on every single (desktop) computing environment know to man :D – Necrolis Jun 21 '12 at 14:46
4
uint32_t get_float_bits(float f) {
    assert(sizeof(float) == sizeof(uint32_t)); // or static assert
    uint32_t bits;
    memcpy(&bits, &f, sizeof f);
    return bits;
}

As of C99, the standard guarantees that the union trick works (provided the sizes match), and implementations have generally guaranteed it even before they were required to. Personally I don't know what people see in it, I prefer this.

If you just want the LSB, and you know the endian-ness, you can access just one byte of the float directly, without any memcpy, or union, or violation of strict aliasing.

int lsb = ((unsigned char*)&f)[0] & 1; // little-endian
int lsb = ((unsigned char*)&f)[sizeof(float)-1] & 1; // big-endian
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 2
    +1 (Actually, the "union trick" is not defined to work in base C99; the language that guarantees its behavior was added in TC2 or 3). – Stephen Canon Jun 21 '12 at 12:33
1

The old trick:

float num = 0.5;
uint32_t binary_representation = *(uint32_t *)#
  • 5
    Violates strict aliasing, *will fail* at high levels of optimization on some compilers. – Steve Jessop Jun 21 '12 at 11:07
  • @SteveJessop Anyway, you're *not supposed to* manually mess with floating-point numbers. –  Jun 21 '12 at 11:10
  • 1
    Maybe, but there's a difference between "you're not supposed to do this because I think you're too stupid to mess with floats", and "you're not supposed to do this because it will unexpectedly break in the release build" :-) – Steve Jessop Jun 21 '12 at 11:12
  • 1
    @H2CO3 Not supposed to by whom? – Andreas Brinck Jun 21 '12 at 11:18
  • By anyone. This is something that is not standard but implementation-defined thing. Floating-point calculations are to be done by the compiler. –  Jun 21 '12 at 11:34
  • @SteveJessop if you think so, then why are you complaining about the high optimization level of the compiler? If you're building with a high optimization set, then you're probably doing a release build, right? Self-contradiction level 100. –  Jun 21 '12 at 11:35
  • 3
    I'm not complaining about the high optimization level, I'm complaining about people writing code that has UB, which manifests as not working at a high optimization level. – Steve Jessop Jun 21 '12 at 11:43
  • You should complain for the question then. I clearly stated my reasoning why. –  Jun 21 '12 at 11:44
  • There's nothing wrong with the question, it clearly states that the implementation uses IEEE floats, so it's understood that any answers will only work on such implementations. This answer has UB, and although I haven't retested it today, I have certainly seen that kind of thing fail on GCC. – Steve Jessop Jun 21 '12 at 11:45
  • @H2CO3 If you know that your compiler uses IEEE-754 floats, there's no problem relying on the binary representation. – Andreas Brinck Jun 21 '12 at 12:51
  • @AndreasBrinck Yes, it's true (and it's mostly the case amongst modern compilers), I only came up with this answer as a response to Steve Jessop's. –  Jun 21 '12 at 13:26
  • H2CO3 The fundamental problem is, that there is a difference between implementation defined behaviour (which is no problem when you know your implementation, like messing with IEEE floats) and undefined behaviour (which is always bad, like the `reinterpret_cast` trick). I have to admit that I also used to do this trick, but it may fail under certain (undefined) circumstances (though working in most cases even if not guaranteed), whereas messing with IEEE bits in general is guaranteed to work, if you know your implementation uses IEEE. – Christian Rau Jun 21 '12 at 13:32
1
#include<stdio.h>
union abc
{
    float fo;
    unsigned int no;
};
int main()
{   
    union abc test;
    test.fo=36.5;
    unsigned int x=test.no;
    for( int i = 0; i < sizeof(float)*8; i++ )
    {
        printf("%d", x & 0x1);
        x = x >> 1;
    }

    return 0;
}

this was a way to extract the bits of the float!

shiladitya
  • 2,290
  • 1
  • 23
  • 36