0

我有一个float, f,在 1 到 0 的范围内,我想映射到一个int, if与以下有关i

f = 1/(2^i)

所以

i = log2(1/f)

我使用以下计算i

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

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

我的问题:

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

5 回答 5

3

假设f是正的,log2(1/f)相当于-log2(f),这应该让你简化一点:

int i=floorf(-log2f(f));

用否定代替除法可能有助于加快速度。

如果您不介意一些完全不可移植的代码,您应该能够直接提取浮点数的指数部分。不过,一个好的实现log2f可能已经这样做了,所以你可能会放弃可移植性而几乎没有回报。

于 2012-05-16T20:48:09.763 回答
2

您应该了解 float 是如何存储的。在使用 4 个字节存储浮点数的典型机器中,最后 1 个字节用于存储二进制指数。如果你可以访问那部分内存,那么你就差不多完成了。

例如。在 C 中,您可以声明一个联合结构来存储 1 个浮点数或 4 个短无符号整数(1 个字节/短整数)。您所要做的就是分配浮点数并提取存储指数的短整数)。

此答案中提到的实际值在您的机器上可能不正确,但如果您知道正确的数字,则可以使用此方法。

于 2012-05-16T20:49:35.103 回答
1

好吧,让我们假设您的浮点数遵循 IEEE754 标准,并且这些值是正确计算的。(可以将您的值正确表示为float,因为f始终是 2 的幂。)

查看 IEEE754 标准,您的数字f将始终*具有尾数 1.0,因此您真正需要的是提取指数。这可以通过使用 的二进制表示来完成float:数字本身是 32 位的,指数 us 位于 24-31 位(从右到左计数)。您需要从该值中减去 127。

例如,请参阅此在线转换器和任何有关 IEEE754 标准的文档以了解更多详细信息。


*好吧,除了非规范化的情况。非规范化浮点数是一种存储方式不是 like1*2^-2而是 like 0.5*2^-1。为了处理非规范化的浮点数,我建议通过添加 0.0 将它们转换为规范化的浮点数。您可以通过尾数不是 1 在您的情况下轻松检测非规范化浮点数。

于 2012-05-17T11:44:23.700 回答
1

让我们看看我是否明白这一点。对于 f=0.5,1/f = 2,因此您希望 i 为 1。对于任何大于 0.5 的 f,1/f 将小于 2,因此 i 将为 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.

所以 i 基本上是尾数前 1 位的从零开始的索引(考虑到指数,应该添加它)

于 2012-05-16T20:47:06.303 回答
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;
}
于 2012-05-17T14:34:17.630 回答