Shift-and-add algorithms

计算对数

为了计算 log ⁡ b x ,   x > 1 \log_bx,\, x>1 logbx,x>1,我们可以预计算表格 (写在硬件上):
A k = log ⁡ b ( 1 + 1 2 k ) ,   k = 0 , 1 , ⋯   , n − 1 A_k = \log_b(1+\dfrac{1}{2^k}),\, k=0,1,\cdots,n-1 Ak=logb(1+2k1),k=0,1,,n1
然后可以做分解
log ⁡ b x ≈ log ⁡ b ∏ k = 0 n − 1 ( 1 + 1 2 k ) a k = ∑ k = 0 n − 1 a k A k \log_b x \approx \log_b \prod_{k=0}^{n-1} (1+\dfrac{1}{2^k})^{a_k} = \sum_{k=0}^{n-1} a_kA_k logbxlogbk=0n1(1+2k1)ak=k=0n1akAk

设置 x 0 = 1 x_0=1 x0=1,依次计算 x i = x i − 1 ( 1 + 1 2 k ) x_{i} = x_{i-1}(1+\dfrac{1}{2^k}) xi=xi1(1+2k1)数次,保证 x i ≤ x x_i \le x xix,以确定 a k a_k ak的大小。直到 n n n长的预计算表格用完。

绝对误差为: O ( log ⁡ b ( 1 + 1 2 n ) ) O(\log_b(1+\dfrac{1}{2^n})) O(logb(1+2n1))

一、预计算表格

void make_shiftadd_ltab(double b)
{
    double l1b = 1.0 / log(b);
    double s = 1.0;
    for (ulong k=0; k<ltab_n; ++k)
    {
        shiftadd_ltab[k] = log(1.0+s) * l1b;  // == log_b(1+1/2^k)
        s *= 0.5;
    }
}

二、计算对数 log ⁡ b x \log_b x logbx

double shiftadd_log(double x, ulong n)
{
    if ( n>=ltab_n )  n = ltab_n;
    double t = 0.0;
    double e = 1.0;
    double v = 1.0;

    for (ulong k=1; k<n; ++k)
    {
        v *= 0.5;  // v == (1>>k)

        double u;
        bool d;
        while ( 1 )
        {
            u = e + e * v;  // u=e;  u+=(e>>k);
            d = ( u<=x );

            if ( d==false )  break;

            t += shiftadd_ltab[k];
            e = u;
        }
    }
    return  t;
}

计算指数

为了计算 b x ,   b > 1 b^x,\, b>1 bx,b>1,我们同样预计算表格 (写在硬件上):
A k = log ⁡ b ( 1 + 1 2 k ) ,   k = 0 , 1 , ⋯   , n − 1 A_k = \log_b(1+\dfrac{1}{2^k}),\, k=0,1,\cdots,n-1 Ak=logb(1+2k1),k=0,1,,n1
然后可以做分解
b x ≈ ∏ i = 0 n − 1 ( 1 + 1 2 k ) a k = b ∑ i = 0 n − 1 a k A k b^x \approx \prod_{i=0}^{n-1}(1+\dfrac{1}{2^k})^{a_k} = b^{\sum_{i=0}^{n-1}a_kA_k} bxi=0n1(1+2k1)ak=bi=0n1akAk

设置 x 0 = 0 x_0=0 x0=0,依次计算 x i = x i − 1 + ( 1 + 1 2 k ) x_{i} = x_{i-1} + (1+\dfrac{1}{2^k}) xi=xi1+(1+2k1)数次,保证 x i ≤ x x_i \le x xix,以确定 a k a_k ak的大小。直到 n n n长的预计算表格用完。

相对误差为: O ( 1 + 1 2 n ) O(1+\dfrac{1}{2^n}) O(1+2n1)

一、预计算表格

void make_shiftadd_ltab(double b)
{
    double l1b = 1.0 / log(b);
    double s = 1.0;
    for (ulong k=0; k<ltab_n; ++k)
    {
        shiftadd_ltab[k] = log(1.0+s) * l1b;  // == log_b(1+1/2^k)
        s *= 0.5;
    }
}

二、计算指数 b x b^x bx

double shiftadd_exp(double x, ulong n)
{
    if ( n>=ltab_n )  n = ltab_n;
    double t = 0.0;
    double e = 1.0;
    double v = 1.0;

    for (ulong k=1; k<n; ++k)
    {
        v *= 0.5;  // v == (1>>k)

        double u;
        bool d;
        while ( 1 )
        {
            u = t + shiftadd_ltab[k];
            d = ( u<=x );

            if ( d==false )  break;

            t = u;
            e += e * v;  // e+=(e>>k);
        }
    }
    return  e;
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐