C 分数到整数映射的高效算法

C 分数到整数映射的高效算法,c,performance,algorithm,C,Performance,Algorithm,我有一个float,f,范围在1到0之间,我想映射到int,If与i相关,通过: f = 1/(2^i) 所以 我使用以下公式计算I: int i = log2f(floorf(1/f)); 这个表达式涉及3个浮点运算,所以我认为它效率相对较低 我的问题是: 一般来说,这是否低效?(我理解这是一个很难回答的问题,因为平台依赖于优化) 有可能创建一个更有效的算法吗?鉴于这涉及到2^n,我想可以使用ints和位移位创建一个更有效的算法 让我们看看我是否明白了。对于f=0.5,1/f=2,所以你

我有一个
float
f
,范围在1到0之间,我想映射到
int
I
f
i
相关,通过:

f = 1/(2^i)
所以

我使用以下公式计算
I

int i = log2f(floorf(1/f)); 
这个表达式涉及3个浮点运算,所以我认为它效率相对较低

我的问题是:

  • 一般来说,这是否低效?(我理解这是一个很难回答的问题,因为平台依赖于优化)
  • 有可能创建一个更有效的算法吗?鉴于这涉及到
    2^n
    ,我想可以使用
    int
    s和位移位创建一个更有效的算法

  • 让我们看看我是否明白了。对于f=0.5,1/f=2,所以你希望我是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.
    

    对于0.5假设
    f
    为正,
    log2(1/f)
    相当于
    -log2(f)
    ,这应该让您简化一点:

    int i=floorf(-log2f(f));
    
    用否定代替除法可以大大加快运算速度


    如果您不介意一些完全不可移植的代码,那么您应该能够直接提取浮点数的指数部分。不过,log2f的良好实现可能已经做到了这一点,因此您可能会放弃可移植性,而很少或根本没有任何回报。

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

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


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

    好吧,假设您的浮点值符合IEEE754标准,并且正确计算了这些值。(可以将您的值正确表示为
    float
    ,因为
    f
    始终是二的幂。)

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

    例如,有关更多详细信息,请参阅本标准和IEEE754标准的任何文档



    *除了非规范化的情况。非规范化浮点存储方式与
    1*2^-2
    不同,而是与
    0.5*2^-1
    类似。对于处理非规范化浮点,我建议通过添加0.0将它们转换为规范化浮点。您可以通过尾数不是1来轻松检测非规范化浮点。

    C有一个用于此目的的函数:frexpf(1999 C标准第7.12.6.4节)。它进行规格化,使指数与[1/2,1]中的分数匹配,因此需要从指数中减去1(例如,对于.25f,它给出的指数为-1,因为.25f=.5*2-1,但需要-2):

    #包括
    #包括
    内部主(空)
    {
    整数指数;
    
    对于(浮球f=0x1p-149f;f@Vlad好接球!已修复。为什么要铺设两次地板?为什么不i=log2f(1/f)?“相对而言”,它与什么有关?在没有FPU的嵌入式系统上,浮点日志函数与整数减法相比速度非常慢,但在现代桌面上,它将比打开文件快得多。@StephenNutt说得好。我把这个短语改为“一般来说”。可能会进行重大的性能优化,但它们都需要缩小问题范围。如果这是针对单CPU体系结构,您需要什么精度?i和f是否有范围限制?对于问题1,不知道执行此操作的频率,无法回答此问题。
    short int
    总是至少是2个字节-也许你的意思是
    int
    ?@BlueRaja DannyPflughoeft在1999年,当我在奔腾II机器上使用C时,short int是1个字节:D正如我提到的,我不确定数字,但使用union是一种方法。
    short
    总是要求至少是两个字节(至少,最早可以追溯到C89)。要么你的编译器非常糟糕,要么你的内存不正确。@BlueRaja DannyPflughoeft,或者,可能是未签名字符。
    int i=floorf(-log2f(f));
    
    #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;
    }