您如何计算浮点数中设置的位数?

时间:2021-09-11 02:59:43

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

如何使用C函数计算浮点数中设置的位数?

5 个解决方案

#1


#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;
}

#2


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.

这样做的地址是f,地址为运算符&。此地址的类型为float *,指向float的指针。然后用(int *)重新创建它,它说“假装这个指针不再指向浮点数,但现在它指向一个int”。请注意,它根本不会更改f处的值。然后最后的*(或者,首先,因为我们从右向左阅读)取消引用这个指针,这是一个指向int的指针,因此返回一个int,a.k.a。这个整数具有与float相同的按位表示。

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

要做相反的事情(转换并将int i返回到浮点数f),请执行相反的操作:

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.

除非我弄错了,否则C标准不会定义此操作,但可能适用于大多数计算机和编译器。它是未定义的,因为我认为数字的实际浮点表示是依赖于实现的,并且可以留给CPU或编译器,因此在此操作之后几乎不可能预测i的值(值相同)反向操作中的f)。它在约翰卡马克的反平方根函数中被用于同样的邪恶目的。

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).

我已经相信你已经知道如何计算常规整数中设置的位数,因为这是一个更容易的任务。如果您不知道,您的编译器(或C语言,我甚至不知道)可能具有计数位的功能,或者您可以使用来自精彩Bit-Twiddling Hacks网站的内容,该网站有办法做事像这样的按位运算(应该非常快)。

#3


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);

#4


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.

你的意思是在一个数字的IEEE-754单精度表示中设置的位?如果是这样,将它转换为int(float和int都是32位宽)并进行常规位计数:问题#109023。

#5


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;
}

#1


#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;
}

#2


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.

这样做的地址是f,地址为运算符&。此地址的类型为float *,指向float的指针。然后用(int *)重新创建它,它说“假装这个指针不再指向浮点数,但现在它指向一个int”。请注意,它根本不会更改f处的值。然后最后的*(或者,首先,因为我们从右向左阅读)取消引用这个指针,这是一个指向int的指针,因此返回一个int,a.k.a。这个整数具有与float相同的按位表示。

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

要做相反的事情(转换并将int i返回到浮点数f),请执行相反的操作:

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.

除非我弄错了,否则C标准不会定义此操作,但可能适用于大多数计算机和编译器。它是未定义的,因为我认为数字的实际浮点表示是依赖于实现的,并且可以留给CPU或编译器,因此在此操作之后几乎不可能预测i的值(值相同)反向操作中的f)。它在约翰卡马克的反平方根函数中被用于同样的邪恶目的。

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).

我已经相信你已经知道如何计算常规整数中设置的位数,因为这是一个更容易的任务。如果您不知道,您的编译器(或C语言,我甚至不知道)可能具有计数位的功能,或者您可以使用来自精彩Bit-Twiddling Hacks网站的内容,该网站有办法做事像这样的按位运算(应该非常快)。

#3


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);

#4


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.

你的意思是在一个数字的IEEE-754单精度表示中设置的位?如果是这样,将它转换为int(float和int都是32位宽)并进行常规位计数:问题#109023。

#5


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;
}