【发布时间】:2009-07-13 18:14:19
【问题描述】:
如何使用 C 函数计算浮点数中设置的位数?
【问题讨论】:
-
用于绩效衡量?
标签: c floating-point
如何使用 C 函数计算浮点数中设置的位数?
【问题讨论】:
标签: c floating-point
#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;
}
【讨论】:
int i; int count=0; for (i = 0; i < 8*sizeof(float); i++) { if ((1 << (i%8)) & focs.cs[i/8]) { count++; } } 压缩这两个循环
CHAR_BIT而不是8(尽管我可以安全地假设sizeof(char) == 1,因为这是根据定义)。
如果你想处理浮点数的实际按位表示,你应该这样做:
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 标准未定义此操作,但可能适用于大多数计算机和编译器。它是未定义的,因为我相信数字的实际浮点表示是依赖于实现的,并且可以留给 CPU 或编译器,因此i 的值在此操作之后几乎是不可能预测的(同样适用于f 在反向操作中的值)。它在约翰卡马克的反平方根函数中被用于同样邪恶的目的。
无论如何,如果您在实际代码中执行此操作,您可能应该停下来三思而后行,思考您要尝试做什么以及为什么要使用floats 来执行此操作。但是,如果您只是出于好奇而这样做,或者您已经考虑过这些并确定您的设计和方法,那就去做吧。
我相信您已经知道如何计算常规整数中设置的位数,因为这是一项更容易的任务。如果你不知道,你的编译器(或 C 语言,我什至不知道)可能有一个计算位数的功能,或者你可以使用来自美妙的 Bit-Twiddling Hacks 网站的东西,它有办法做类似的事情这与按位运算(应该很快)。
【讨论】:
char 除外)的指针永远不会指向同一个对象的假设(来自 ISO C,这有利于性能)。
第一个答案提到的整数中的一个很好的计数设置位的函数:
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);
【讨论】:
您的意思是数字的 IEEE-754 单精度表示中设置的位?如果是这样,请将其转换为 int(float 和 int 都是 32 位宽)并进行常规位计数:SO question #109023。
【讨论】:
unsigned int*)&f。无符号类型表现更好(没有符号混乱)。
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;
}
【讨论】: