通过分离有效数和指数来近似log2(浮点数)

时间:2014-10-23 18:24:32

标签: c math approximation function-approximation

问题

我正在尝试实现一个快速浮点数= log2(浮点数)。我写了一个简单的C程序来比较我的结果和log2,我得到一个小错误,我无法找到它的来源。

背景

我采用识别浮点表示(忽略符号位)的方法是2^(exponent) * 1.significand。使用日志属性我得到log2(float) = exp + log2(1.significand)。最终我会截断表查找的有效数字,但是现在我想验证正确的结果。

有关灵感的进一步背景阅读:http://www.icsi.berkeley.edu/pubs/techreports/TR-07-002.pdf

这就是问题所在。这是一个简单的程序,它提取浮点位并将指数加到log2(有效数字)。

#include <math.h>
#include <stdint.h>
#include <stdio.h>

int main()
{
    typedef union {
      int32_t i;
      float f;
    } poly32_t;

    float x = 31415926535.8;
    poly32_t one;
    one.f = 1.0f;

    uint32_t ii;
    uint32_t num_iter = 15;
    for(ii=0; ii < num_iter; ++ii) {
        poly32_t poly_x;
        poly32_t poly_x_exponent;
        poly32_t poly_x_significand;

        // extract the exponent and significand
        poly_x.f = x;
        poly_x_significand.i = (0x007fffff & poly_x.i);
        poly_x_exponent.i = (0xff & (poly_x.i >> 23) ) - 127;

        // recover the hidden 1 of significand
        poly_x_significand.f = 1.0 + ((float)poly_x_significand.i)/10000000;
        // log2(2^exp * sig) = exponent + log2(significand)
        float log_sig = log2(poly_x_significand.f);
        float y_approx = (float)poly_x_exponent.i + log_sig;

        // Get the actual value
        float y_math = log2(x);
        printf("math::log2(%16.4f)=%8.4f  ;  approx=%8.4f  ;  diff=%.4f\n",
                                x, y_math,      y_approx, y_math-y_approx);
        x *= 0.1;
    }
    return 1;
}

输出

math::log2(31415926784.0000)= 34.8708  ;  approx= 34.7614  ;  diff=0.1094
math::log2( 3141592576.0000)= 31.5488  ;  approx= 31.4733  ;  diff=0.0755
math::log2(  314159264.0000)= 28.2269  ;  approx= 28.1927  ;  diff=0.0342
math::log2(   31415926.0000)= 24.9050  ;  approx= 24.7924  ;  diff=0.1126
math::log2(    3141592.5000)= 21.5831  ;  approx= 21.5036  ;  diff=0.0794
math::log2(     314159.2500)= 18.2611  ;  approx= 18.2221  ;  diff=0.0390
math::log2(      31415.9258)= 14.9392  ;  approx= 14.8235  ;  diff=0.1158
math::log2(       3141.5925)= 11.6173  ;  approx= 11.5340  ;  diff=0.0833
math::log2(        314.1592)=  8.2954  ;  approx=  8.2517  ;  diff=0.0437
math::log2(         31.4159)=  4.9734  ;  approx=  4.8546  ;  diff=0.1188
math::log2(          3.1416)=  1.6515  ;  approx=  1.5644  ;  diff=0.0871
math::log2(          0.3142)= -1.6704  ;  approx= -1.7187  ;  diff=0.0483
math::log2(          0.0314)= -4.9924  ;  approx= -4.9936  ;  diff=0.0012
math::log2(          0.0031)= -8.3143  ;  approx= -8.4050  ;  diff=0.0907
math::log2(          0.0003)=-11.6362  ;  approx=-11.6890  ;  diff=0.0528

&#34;近似&#34;此时应该与clib的log2完全相同;任何帮助识别我的错误将不胜感激。

1 个答案:

答案 0 :(得分:5)

编辑(2)删除有效位数的错误信息

此外,我认为这是错误的:

    // recover the hidden 1 of significand
    poly_x_significand.f = 1.0 + ((float)poly_x_significand.i)/10000000;

有效数字的(显式部分)是二进制分数,而不是十进制分数。你应该除以(float) (1 << 23)

另请注意,您的实现与正常数字的匹配不正确。