我有一个float
,f
,在1到0的范围内,我要映射到int
,i
。 f
与i
相关:
f = 1/(2^i)
所以
i = log2(1/f)
我正在使用以下内容来计算i
:
int i = log2f(floorf(1/f));
这个表达式涉及3个浮点运算,所以我认为它的效率相对较低。
我的问题:
2^n
我想可以使用int
和位移来创建更有效的算法。答案 0 :(得分:3)
假设f
为正,log2(1/f)
相当于-log2(f)
,这可以让您简化一下:
int i=floorf(-log2f(f));
用否定代替分裂可能有助于提高速度。
如果您不介意一些完全不可移植的代码,您应该能够直接提取浮点数的指数部分。 log2f
的良好实现可能已经可以做到这一点,所以你可能会放弃很少或根本没有的可移植性。
答案 1 :(得分:2)
你应该知道如何存储浮点数。在使用4个字节存储浮点数的典型机器中,最后1个字节用于存储二进制指数。如果你可以访问那部分内存,那么你差不多完成了。
EG。在C中,您可以声明一个union结构来存储1个float或4个short unsigned int(1个字节/ short int)。您所要做的就是分配float并提取存储指数的short int。
本答案中提到的实际值可能在您的机器上不正确,但如果您知道正确的数字,则可以使用此方法。
答案 2 :(得分:1)
让我们看看我是否直截了当。对于f = 0.5,1 / f = 2,所以你希望i为1.对于任何大于0.5的f,1 / f将小于2,所以我将为0,对吧?
For 0.5<f<=1 i=0
For 0.25<f<0.5 i=1
For 0.125<f<0.25 i=2
and so on.
所以我基本上是尾数的前1位的从零开始的索引(考虑到应该添加到它的指数)
答案 3 :(得分:1)
好吧,我们假设您的浮点符合IEEE754标准,并且正确计算了这些值。 (可以将您的值正确表示为float
,因为f
始终是2的幂。)
查看IEEE754标准,您的号码f
将始终*具有尾数1.0,因此您真正需要的是提取指数。这可以通过使用float
的二进制表示来完成:数字本身是32位,而指数我们位于第24-31位(从右到左计数)。您需要从值中减去127。
有关更多详细信息,请参阅此online converter以及有关IEEE754标准的任何文档。
*好吧,除了非规范化的案例。非规范化浮点数不像1*2^-2
那样存储,而是像0.5*2^-1
那样存储。为了处理非规范化浮点数,我建议通过添加0.0将它们转换为规范化浮点数。在你的情况下,你可以通过尾数不是1来轻松检测非规范化浮点数。
答案 4 :(得分:1)
C具有用于此目的的功能:frexpf(1999 C标准第7.12.6.4节)。它正则化,因此指数匹配[1 / 2,1}中的分数,因此您需要从其指数中减去1(例如,对于.25f,它给出-1的指数,因为.25f = .5 * 2 -1 ,但你想-2):
#include <math.h>
#include <stdio.h>
int main(void)
{
int exponent;
for (float f = 0x1p-149f; f <= 1; f += f)
{
frexpf(f, &exponent);
printf("The exponent of %a is %d.\n", f, exponent-1);
}
return 0;
}