通过对负指数进行平方来加权

时间:2015-06-20 21:16:51

标签: c algorithm math recursion

我不确定通过平方的权力是否能解决负指数。我实现了以下代码,仅适用于正数。

    #include <stdio.h>
    int powe(int x, int exp)
    {
         if (x == 0)
            return 1;
         if (x == 1)
            return x;
         if (x&1)
                return powe(x*x, exp/2);
         else
                return x*powe(x*x, (exp-1)/2);       
    }

查看https://en.wikipedia.org/wiki/Exponentiation_by_squaring并不会有所帮助,因为以下代码似乎有误。

    Function exp-by-squaring(x, n ) 
      if n < 0  then return exp-by-squaring(1 / x, - n );
      else if n = 0  then return  1;
      else if n = 1  then return  x ; 
      else if n is even  then return exp-by-squaring(x * x,  n / 2);
      else if n is odd  then return x * exp-by-squaring(x * x, (n - 1) / 2).

编辑: 感谢amit这个解决方案适用于负数和正数:

    float powe(float x, int exp)
    {
            if (exp < 0)
                    return powe(1/x, -exp);
            if (exp == 0)
                    return 1;
            if (exp == 1)
                    return x;
            if (((int)exp)%2==0)
                    return powe(x*x, exp/2);
            else
                    return x*powe(x*x, (exp-1)/2);
    }

对于分数指数,我们可以在下面做(Spektre方法):

  1. 假设您有x ^ 0.5,那么您可以通过此方法轻松计算平方根:从0开始到x / 2并继续检查x ^ 2是否等于binary search method中的结果。< / p>

  2. 所以,如果你有x ^(1/3),你必须将if mid*mid <= n替换为if mid*mid*mid <= n,你将得到x的立方根。适用于x ^的东西(1/4),x ^(1/5)等。在x ^(2/5)的情况下,我们可以做(x ^(1/5))^ 2并再次减少找到x的第5个根的问题。

  3. 但是到了这个时候你会意识到这个方法只适用于可以将根目录转换为1 / x格式的情况。如果我们无法转换,我们会陷入困境吗?不,我们仍然可以按照我们的意愿行事。

  4. 将浮点数转换为固定点,然后计算pow(a,b)。假设该数字是0.6,将其转换为(24,8)浮点产生Floor(0.6 * 1 <&lt; 8)= 153(10011001)。如你所知153表示小数部分所以在固定点这个(10011001)代表(2 ^ -1,0,0,2 ^ -3,2 ^ -4,0,0,2 ^ 7)。所以我们可以再次通过计算固定点x的2,3,4和7根来计算pow(a,0.6)。在计算之后,我们再次需要通过除以1 <&lt; 8来获得浮点结果。

  5. 上述方法的代码可以在接受的答案中找到。

    还有基于日志的方法

    x^y = exp2(y*log2(x))

1 个答案:

答案 0 :(得分:4)

整数示例适用于32位int算术,DWORD为32位unsigned int

  1. 浮动pow(x,y)=x^y

    通常评估如下:

    因此可以评估小数指数:pow(x,y) = exp2(y*log2(x))。这也可以在固定点上完成:

  2. 整数pow(a,b)=a^b其中a>=0 , b>=0

    这很简单(你已经有了)通过平方来完成:

        DWORD powuu(DWORD a,DWORD b)
            {   
            int i,bits=32;
            DWORD d=1;
            for (i=0;i<bits;i++)
                {
                d*=d;
                if (DWORD(b&0x80000000)) d*=a;
                b<<=1;
                }
            return d;
            }
    
  3. 整数pow(a,b)=a^b其中b>=0

    只需添加几个if来处理否定的a

        int powiu(int a,DWORD b)
         {
         int sig=0,c;
         if ((a<0)&&(DWORD(b&1)) { sig=1; a=-a; } // negative output only if a<0 and b is odd
         c=powuu(a,b); if (sig) c=-c;
         return c;
         }
    
  4. 整数pow(a,b)=a^b

    所以,如果b<0则意味着1/powiu(a,-b)正如您所看到的那样,结果根本不是整数,所以要么忽略这种情况,要么返回浮动值或添加乘数变量(这样您就可以评估{{}关于纯整数算术的1}}方程式)。这是浮点结果:

    PI
  5. 整数 float powfii(int a,int b) { if (b<0) return 1.0/float(powiu(a,-b)); else return powiu(a,b); } 其中pow(a,b)=a^b是小数

    您可以执行b这样的事情,其中​​a^(1/bb)是整数。实际上这是生根,因此您可以使用二进制搜索来评估:

    • bba^(1/2)
    • square root(a)a^(1/bb)

    MSB LSB 进行bb_root(a)的二分搜索,然后评估c是否保留pow(c,bb)<=a否则清楚它。这是bit示例:

    sqrt

    所以现在只需将 int bits(DWORD p) // count how many bits is p { DWORD m=0x80000000; int b=32; for (;m;m>>=1,b--) if (p>=m) break; return b; } DWORD sqrt(const DWORD &x) { DWORD m,a; m=(bits(x)>>1); if (m) m=1<<m; else m=1; for (a=0;m;m>>=1) { a|=m; if (a*a>x) a^=m; } return a; } 更改为if (a*a>x),其中if (pow(a,bb)>x) ...所以bb=1/b是您要查找的小数指数,b是整数。此外,bb是结果的位数,因此将m更改为m=(bits(x)>>1);

  6. [edit1]固定点sqrt示例

    m=(bits(x)/bb);

    所以这是无符号的定点。高//--------------------------------------------------------------------------- const int _fx32_fract=16; // fractional bits count const int _fx32_one =1<<_fx32_fract; DWORD fx32_mul(const DWORD &x,const DWORD &y) // unsigned fixed point mul { DWORD a=x,b=y; // asm has access only to local variables asm { // compute (a*b)>>_fx32_fract mov eax,a // eax=a mov ebx,b // ebx=b mul eax,ebx // (edx,eax)=eax*ebx mov ebx,_fx32_one div ebx // eax=(edx,eax)>>_fx32_fract mov a,eax; } return a; } DWORD fx32_sqrt(const DWORD &x) // unsigned fixed point sqrt { DWORD m,a; if (!x) return 0; m=bits(x); // integer bits if (m>_fx32_fract) m-=_fx32_fract; else m=0; m>>=1; // sqrt integer result is half of x integer bits m=_fx32_one<<m; // MSB of result mask for (a=0;m;m>>=1) // test bits from MSB to 0 { a|=m; // bit set if (fx32_mul(a,a)>x) // if result is too big a^=m; // bit clear } return a; } //--------------------------------------------------------------------------- 位是整数,低16位是小数部分。

    • 这是fp - &gt; fx转换:16
    • 这是fp&lt; - fx转换:DWORD(float(x)*float(_fx32_one))
    • float(DWORD(x))/float(_fx32_one))fx32_mul(x,y)它使用80386 + 32位架构的汇编程序(您可以将其重写为karatsuba或其他任何与平台无关的内容)
    • x*yfx32_sqrt(x)

      在固定点,您应该知道乘法的小数位移:sqrt(x)您需要向后移(a<<16)*(b<<16)=(a*b<<32)才能获得结果>>16。结果也会溢出(a*b<<16)位因此我在汇编中使用32位结果。

    [edit2] 32位签名定点pow C ++示例

    当你把所有前面的步骤放在一起时,你应该有这样的东西:

    64

    我已经测试了这样:

    //---------------------------------------------------------------------------
    //--- 32bit signed fixed point format (2os complement)
    //---------------------------------------------------------------------------
    // |MSB              LSB|
    // |integer|.|fractional|
    //---------------------------------------------------------------------------
    const int _fx32_bits=32;                                // all bits count
    const int _fx32_fract_bits=16;                          // fractional bits count
    const int _fx32_integ_bits=_fx32_bits-_fx32_fract_bits; // integer bits count
    //---------------------------------------------------------------------------
    const int _fx32_one       =1<<_fx32_fract_bits;         // constant=1.0 (fixed point)
    const float _fx32_onef    =_fx32_one;                   // constant=1.0 (floating point)
    const int _fx32_fract_mask=_fx32_one-1;                 // fractional bits mask
    const int _fx32_integ_mask=0xFFFFFFFF-_fx32_fract_mask; // integer bits mask
    const int _fx32_sMSB_mask =1<<(_fx32_bits-1);           // max signed bit mask
    const int _fx32_uMSB_mask =1<<(_fx32_bits-2);           // max unsigned bit mask
    //---------------------------------------------------------------------------
    float fx32_get(int   x) { return float(x)/_fx32_onef; }
    int   fx32_set(float x) { return int(float(x*_fx32_onef)); }
    //---------------------------------------------------------------------------
    int fx32_mul(const int &x,const int &y) // x*y
        {
        int a=x,b=y;                // asm has access only to local variables
        asm {                       // compute (a*b)>>_fx32_fract
            mov eax,a
            mov ebx,b
            mul eax,ebx             // (edx,eax)=a*b
            mov ebx,_fx32_one
            div ebx                 // eax=(a*b)>>_fx32_fract
            mov a,eax;
            }
        return a;
        }
    //---------------------------------------------------------------------------
    int fx32_div(const int &x,const int &y) // x/y
        {
        int a=x,b=y;                // asm has access only to local variables
        asm {                       // compute (a*b)>>_fx32_fract
            mov eax,a
            mov ebx,_fx32_one
            mul eax,ebx             // (edx,eax)=a<<_fx32_fract
            mov ebx,b
            div ebx                 // eax=(a<<_fx32_fract)/b
            mov a,eax;
            }
        return a;
        }
    //---------------------------------------------------------------------------
    int fx32_abs_sqrt(int x)            // |x|^(0.5)
        {
        int m,a;
        if (!x) return 0;
        if (x<0) x=-x;
        m=bits(x);                  // integer bits
        for (a=x,m=0;a;a>>=1,m++);  // count all bits
        m-=_fx32_fract_bits;        // compute result integer bits (half of x integer bits)
        if (m<0) m=0; m>>=1;
        m=_fx32_one<<m;             // MSB of result mask
        for (a=0;m;m>>=1)           // test bits from MSB to 0
            {
            a|=m;                   // bit set
            if (fx32_mul(a,a)>x)    // if result is too big
             a^=m;                  // bit clear
            }
        return a;
        }
    //---------------------------------------------------------------------------
    int fx32_pow(int x,int y)       // x^y
        {
        // handle special cases
        if (!y) return _fx32_one;                           // x^0 = 1
        if (!x) return 0;                                   // 0^y = 0  if y!=0
        if (y==-_fx32_one) return fx32_div(_fx32_one,x);    // x^-1 = 1/x
        if (y==+_fx32_one) return x;                        // x^+1 = x
        int m,a,b,_y; int sx,sy;
        // handle the signs
        sx=0; if (x<0) { sx=1; x=-x; }
        sy=0; if (y<0) { sy=1; y=-y; }
        _y=y&_fx32_fract_mask;      // _y fractional part of exponent
         y=y&_fx32_integ_mask;      //  y integer part of exponent
        a=_fx32_one;                // ini result
        // powering by squaring x^y
        if (y)
            {
            for (m=_fx32_uMSB_mask;(m>_fx32_one)&&(m>y);m>>=1);     // find mask of highest bit of exponent
            for (;m>=_fx32_one;m>>=1)
                {
                a=fx32_mul(a,a);
                if (int(y&m)) a=fx32_mul(a,x);
                }
            }
        // powering by rooting x^_y
        if (_y)
            {
            for (b=x,m=_fx32_one>>1;m;m>>=1)                            // use only fractional part
                {
                b=fx32_abs_sqrt(b);
                if (int(_y&m)) a=fx32_mul(a,b);
                }
            }
        // handle signs
        if (sy) { if (a) a=fx32_div(_fx32_one,a); else a=0; /*Error*/ }     // underflow
        if (sx) { if (_y) a=0; /*Error*/ else if(int(y&_fx32_one)) a=-a; }  // negative number ^ non integer exponent, here could add test if 1/_y is integer instead
        return a;
        }
    //---------------------------------------------------------------------------
    
    • float a,b,c0,c1,d; int x,y; for (a=0.0,x=fx32_set(a);a<=10.0;a+=0.1,x=fx32_set(a)) for (b=-2.5,y=fx32_set(b);b<=2.5;b+=0.1,y=fx32_set(b)) { if (!x) continue; // math pow has problems with this if (!y) continue; // math pow has problems with this c0=pow(a,b); c1=fx32_get(fx32_pow(x,y)); d=0.0; if (fabs(c1)<1e-3) d=c1-c0; else d=(c0/c1)-1.0; if (fabs(d)>0.1) d=d; // here add breakpoint to check inconsistencies with math pow } 是浮点
    • a,bx,y
    • 最接近的定点表示形式
    • a,b是数学效力结果
    • c0是fx32_pow结果
    • c1是差异

      希望没有忘记一些微不足道的事情,但似乎它运作正常。不要忘记固定点的精度非常有限,因此结果会略有不同......

    P.S。看看这个: