Как бы вы посчитали количество бит, установленных в числе с плавающей запятой? - PullRequest
5 голосов
/ 13 июля 2009

Как вы подсчитываете количество бит, установленных в числе с плавающей запятой, используя функции C?

Ответы [ 5 ]

6 голосов
/ 13 июля 2009
#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;
}
4 голосов
/ 13 июля 2009

Если вы хотите работать с фактическим побитовым представлением числа с плавающей запятой, вы должны сделать что-то вроде этого:

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

Для этого нужно взять адрес f с адресом оператора, &. Этот адрес имеет тип float *, указатель на число с плавающей точкой. Затем он переписывает его с помощью (int *), который говорит: «притворитесь, что этот указатель больше не указывает на float, но теперь он указывает на int». Обратите внимание, что это не меняет значение на f. Затем последний * (или первый, поскольку мы читаем справа налево) разыменовывает этот указатель, который является указателем на int, и поэтому возвращает int, то есть целое число с таким же побитовым представлением, как поплавок.

Чтобы сделать обратное (преобразовать и int i обратно в float f), сделать наоборот:

f = *(float *)&i;

Если я не ошибаюсь, эта операция не определена стандартом C, но, вероятно, будет работать на большинстве компьютеров и компиляторов. Он не определен, потому что я считаю, что фактическое представление чисел с плавающей запятой зависит от реализации и может быть оставлено на усмотрение ЦП или компилятора, и поэтому значение i почти невозможно предсказать после этой операции (то же самое относится и к значение f в обратном порядке). Это классно используется в функции обратного квадратного корня Джона Кармака для той же гнусной цели.

В любом случае, если вы делаете это в реальном коде, вам, вероятно, следует остановиться и дважды подумать о том, что вы пытаетесь сделать и почему вы используете float s для этого. Однако, если вы просто делаете это из любопытства, или вы подумали об этом и уверены в своем дизайне и методах, сделайте это.

Меня убеждают, что вы уже знаете, как считать количество битов, установленных в обычном целом числе, поскольку это гораздо более простая задача. Если вы не знаете, ваш компилятор (или язык C, я даже не знаю) может иметь функцию для подсчета битов, или вы можете использовать что-то с замечательного Bit-Twiddling Hacks сайта, у которого есть способы делать такие вещи с помощью побитовых операций (что должно быть довольно быстро).

3 голосов
/ 13 июля 2009

Хорошая функция для подсчета установленных битов в целом числе, упомянутом в первом ответе:

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

Чтобы использовать его на вашем поплавке, вы должны сделать что-то вроде этого:

//...
float f;
//...
int numBitsOfF = NumberOfSetBits(*(int*) &f);
2 голосов
/ 13 июля 2009

Вы имеете в виду биты, установленные в представлении числа IEEE-754 с одинарной точностью?Если это так, приведите его к типу int (и float, и int имеют ширину 32 бита) и выполните регулярный подсчет битов: SO question # 109023 .

0 голосов
/ 14 июля 2009
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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...