tags:

views:

719

answers:

5

How do you count the number of bits set in a floating point number using C functions?

+2  A: 

You mean the bits set in the IEEE-754 single precision representation of a number? If so, cast it to int (both float and int are 32bit wide) and do a regular bit count: SO question #109023.

Adrian Panasiuk
Casting to int will truncate and convert, not give you the raw representation.
bdonlan
Adrian Panasiuk
I think Adrian meant casting the pointer, not the value.
Nikolai N Fetissov
Adrian Panasiuk
Hi all,It would be great if i could get with some edxamples
http://stackoverflow.com/questions/109023/best-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer
Adrian Panasiuk
I took all that time to write out the answer. Damn...
Chris Lutz
Chris,Thanks a lot
Johannes Schaub - litb
+4  A: 

If you want to work on the actual bitwise representation of a floating point number, you should do something like this:

float f; /* whatever your float is */
int i = *(int *)&f;

What this does is take the address of f with the address-of operator, &. This address is of type float *, a pointer to a float. Then it recasts it with (int *), which says "pretend this pointer doesn't point to a float anymore, but now it points to an int". Note that it doesn't change the value at f at all. Then the last * (or first, since we read right-to-left) dereferences this pointer, which is a pointer to an int, and therefore returns an int, a.k.a. the integer with the same bitwise representation as the float.

To do the opposite (convert and int i back to a float f), do the opposite:

f = *(float *)&i;

Unless I am mistaken, this operation is undefined by the C standard, but will probably work on most computers and compilers. It is undefined because I believe the actual floating-point representation of numbers is implementation-dependent, and can be left to the CPU or the compiler, and therefore the value of i is almost impossible to predict after this operation (same goes for the value of f in the reverse operation). It is famously used in John Carmack's inverse square root function for the same nefarious purpose.

Anyway, if you're doing this in real code, you should probably stop and think twice about what you're trying to do and why you're using floats to do it. However, if you're just doing this out of curiosity, or you have thought about these and are sure of your design and methods, go for it.

I'm led to believe that you already know how to count the number of bits set in a regular integer, as this is a much easier task. If you don't know, your compiler (or the C language, I don't even know) may have a function to count bits, or you could use something from the wonderful Bit-Twiddling Hacks website, which has ways to do things like this with bitwise operations (which should be pretty fast).

Chris Lutz
It's undefined not just because of that -- GCC (in certain configurations) will warn **dereferencing type-punned pointer will break strict-aliasing rules** with good reason, as this really does break the assumption (from ISO C that benefits performance) that two pointers to distinct simple types (other than `char`) never point to the same object.
ephemient
Where are the two pointers here?
sigjuice
ephemient
Steve Jessop
+5  A: 
#include <stdio.h>  /* for printf() */
#include <limits.h> /* for CHAR_BIT */

int main(void) {
  /* union method */
  {
    /* a union can only be initialized for the first option in the union */
    union { float f; char cs[sizeof(float)]; } const focs = { 1.0 };
    int j,k;
    int count = 0;
    for (j = 0; j < sizeof(float); j++)
    {
      char const byte = focs.cs[j];
      for (k = 0; k < CHAR_BIT; k++)
      {
        if ((1 << k) & byte)
        {
          count++;
        }
      }
    }
    printf("count(%2.1f) = %d\n", focs.f, count);
  }
  /* cast method */
  {
    float const f = 2.5;
    int j,k; 
    int count = 0;
    for (j = 0; j < sizeof(float); j++)
    {
      char const byte = ((char *)&f)[j];
      for (k = 0; k < CHAR_BIT; k++)
      {
        if ((1 << k) & byte)
        {
          count++;
        }
      }
    }
    printf("count(%2.1f) = %d\n", f, count);
  }
  return 0;
}
rampion
I forgot about the union hack! But you should use sizeof(float) instead of sizeof(int). Also, int and float are the same size on most systems, but I can't find any standards saying anything about their relative sizes (or anything about float sizes), so I can't be sure - but wouldn't it be nicer to only have 1 for() loop and use a union of float and int instead?
Chris Lutz
That's the thing - I think implementation-wise, they're almost always the same, but I don't know of any standard that dictates so, which is why I did it this way. I could still compress the two loops by doing `int i; int count=0; for (i = 0; i < 8*sizeof(float); i++) { if ((1 << (i%8)) } }`
rampion
Allthough by this(http://stackoverflow.com/questions/881894/is-char-guaranteed-to-be-exactly-8-bit-long-in-c) I should be using `CHAR_BIT` instead of 8 (though I safe with assuming `sizeof(char) == 1`, since that's by definition).
rampion
sizeof(char) will always be 1, but your code could (theoretically) be running on a PDP-7, where CHAR_BIT would be 18 (!).
Chris Lutz
+3  A: 

A nice function for counting set bits in an integer mentioned by the first answer:

int NumberOfSetBits(int i)
{
    i = i - ((i >> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
    return ((i + (i >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
}

To use it on your float you would do something like this:

//...
float f;
//...
int numBitsOfF = NumberOfSetBits(*(int*) &f);
dborba
Thanks a lot everybody for the support
A: 
The following function will find the number of bits in a 32-bit number. Just type case your float with integer and call this function by a cast 
float f=3.14f;
count_bits(*(int *)&f);

int count_bits(int v)
{
    // count the number of bits set in v
    int c; // c accumulates the total bits set in v
    int b=v;
    for (c = 0; v; c++)
    {
            v &= v - 1; // clear the least significant bit set
    }
    //printf("No of bits in %d is %d\n",b,c);
    return c;
}
Saradhi