【问题标题】:How would you count the number of bits set in a floating point number?您将如何计算浮点数中设置的位数?
【发布时间】:2009-07-13 18:14:19
【问题描述】:

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

【问题讨论】:

  • 用于绩效衡量?

标签: c floating-point


【解决方案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;
}

【讨论】:

  • 我忘记了联合黑客!但是你应该使用 sizeof(float) 而不是 sizeof(int)。此外, int 和 float 在大多数系统上的大小相同,但我找不到任何标准说明它们的相对大小(或任何关于浮点大小的内容),所以我不能确定 - 但它会不会更好只有 1 个 for() 循环并使用 float 和 int 的联合?
  • 就是这样 - 我认为在实施方面,它们几乎总是相同的,但我不知道有什么标准规定了这一点,这就是我这样做的原因。我仍然可以通过 int i; int count=0; for (i = 0; i &lt; 8*sizeof(float); i++) { if ((1 &lt;&lt; (i%8)) &amp; focs.cs[i/8]) { count++; } } 压缩这两个循环
  • 尽管如此(stackoverflow.com/questions/881894/…)我应该使用CHAR_BIT而不是8(尽管我可以安全地假设sizeof(char) == 1,因为这是根据定义)。
  • sizeof(char) 将始终为 1,但您的代码可以(理论上)在 PDP-7 上运行,其中 CHAR_BIT 为 18 (!)。
【解决方案2】:

如果你想处理浮点数的实际按位表示,你应该这样做:

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

它的作用是使用地址运算符&amp; 获取f 的地址。这个地址的类型是float *,一个指向浮点数的指针。然后它用(int *) 重铸它,上面写着“假设这个指针不再指向float,但现在它指向int”。请注意,它根本不会更改 f 的值。然后最后一个*(或第一个,因为我们从右到左阅读)取消引用这个指针,它是一个指向int的指针,因此返回一个int,也就是具有相同按位表示的整数浮动。

要做相反的事情(将int i转换回float f),做相反的事情:

f = *(float *)&i;

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

无论如何,如果您在实际代码中执行此操作,您可能应该停下来三思而后行,思考您要尝试做什么以及为什么要使用floats 来执行此操作。但是,如果您只是出于好奇而这样做,或者您已经考虑过这些并确定您的设计和方法,那就去做吧。

我相信您已经知道如何计算常规整数中设置的位数,因为这是一项更容易的任务。如果你不知道,你的编译器(或 C 语言,我什至不知道)可能有一个计算位数的功能,或者你可以使用来自美妙的 Bit-Twiddling Hacks 网站的东西,它有办法做类似的事情这与按位运算(应该很快)。

【讨论】:

  • 它未定义不仅仅是因为——GCC(在某些配置中)会警告取消引用类型双关指针会破坏严格的别名规则有充分的理由,因为这真的确实打破了两个指向不同简单类型(char 除外)的指针永远不会指向同一个对象的假设(来自 ISO C,这有利于性能)。
  • @sigjuice:这两个指针是通过 &f 创建的 float* 和通过强制转换 float* 创建的 int*。编译器完全有权重新排序内存访问操作,以便在 f 初始化之前将内存位置读入 i,这就是行为未定义的原因。
【解决方案3】:

第一个答案提到的整数中的一个很好的计数设置位的函数:

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

【讨论】:

  • 非常感谢大家的支持
【解决方案4】:

您的意思是数字的 IEEE-754 单精度表示中设置的位?如果是这样,请将其转换为 int(float 和 int 都是 32 位宽)并进行常规位计数:SO question #109023

【讨论】:

  • 转换为 int 会截断和转换,而不是为您提供原始表示。
  • 好点。因此,更好的解决方案是将它合并或浮动 f; (int)&f
  • 大家好,如果我能得到一些 edxamples 那就太好了
  • 我会使用 *(unsigned int*)&amp;f。无符号类型表现更好(没有符号混乱)。
【解决方案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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    相关资源
    最近更新 更多