用于将分数映射到整数的高效算法

时间:2012-05-16 20:37:02

标签: c performance algorithm

我有一个floatf,在1到0的范围内,我要映射到intifi相关:

f = 1/(2^i)

所以

i = log2(1/f)

我正在使用以下内容来计算i

int i = log2f(floorf(1/f)); 

这个表达式涉及3个浮点运算,所以我认为它的效率相对较低。

我的问题:

  1. 一般来说,这效率低吗? (我很欣赏由于平台相关的优化,这很难回答)
  2. 是否有可能创建更有效的算法?看到这涉及2^n我想可以使用int和位移来创建更有效的算法。

5 个答案:

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