Karatsuba乘法算法与模块化约简

时间:2015-03-07 22:58:24

标签: algorithm multiplication modular-arithmetic

我试图估计将两个大位数乘以一些大素数的时间。我的计算能力仅限于添加,乘法和存储32位数字。

由于这个原因,我想使用Karatsuba algorithm,因为乘法被简化为单位数运算。但是,该算法不包含模块化缩减。

我的另一个想法是使用Montgomery reduction,但鉴于我的计算限制,我不确定这将如何执行。

您建议我使用哪种算法?

1 个答案:

答案 0 :(得分:0)

这不是答案,但在评论

中这是不可读的
  • 它只是说明Karatsuba代码的样子

这是我对任意浮点数的Karatsuba乘法的实现

//---------------------------------------------------------------------------
void arbnum::_mul_karatsuba(DWORD *z,DWORD *x,DWORD *y,int n)
    {
    // recursion for karatsuba
    // z[2n]=x[n]*y[n]; n=2^m
    int i;    for (i=0;i<n;i++) if (x[i]) { i=-1; break; }      // x==0 ?
    if (i< 0) for (i=0;i<n;i++) if (y[i]) { i=-1; break; }      // y==0 ?
    if (i>=0){for (i=0;i<n+n;i++) z[i]=0; return; }             // 0.? = 0
    if (n==1) { alu.mul(z[0],z[1],x[0],y[0]); return; }
    if (n< 1) return;
    int n2=n>>1;
    _mul_karatsuba(z+n,x+n2,y+n2,n2);                           // z0 = x0.y0
    _mul_karatsuba(z  ,x   ,y   ,n2);                           // z2 = x1.y1
    DWORD *q=new DWORD[n<<1],*q0,*q1,*qq; BYTE cx,cy;
    if (q==NULL) { _error(_arbnum_error_NotEnoughMemory); return; }
    #define _add { alu.add(qq[i],q0[i],q1[i]); for (i--;i>=0;i--) alu.adc(qq[i],q0[i],q1[i]); } // qq=q0+q1 ...[i..0]
    #define _sub { alu.sub(qq[i],q0[i],q1[i]); for (i--;i>=0;i--) alu.sbc(qq[i],q0[i],q1[i]); } // qq=q0-q1 ...[i..0]
    qq=q;    q0=x+n2; q1=x;   i=n2-1; _add; cx=alu.cy;          // =x0+x1
    qq=q+n2; q0=y+n2; q1=y;   i=n2-1; _add; cy=alu.cy;          // =y0+y1
    _mul_karatsuba(q+n,q+n2,q,n2);                              // =(x0+x1)(y0+y1) mod ((2^N)-1)
    if (cx) { qq=q+n; q0=qq; q1=q+n2; i=n2-1; _add; cx=alu.cy; }// +=cx*(y0+y1)<<n2
    if (cy) { qq=q+n; q0=qq; q1=q   ; i=n2-1; _add; cy=alu.cy; }// +=cy*(x0+x1)<<n2
    qq=q+n;  q0=qq;   q1=z+n; i=n-1;  _sub;                     // -=z0
    qq=q+n;  q0=qq;   q1=z;   i=n-1;  _sub;                     // -=z2
    qq=z+n2; q0=qq;   q1=q+n; i=n-1;  _add;                     // z1=(x0+x1)(y0+y1)-z0-z2
    for (i=n2-1;i>=0;i--) if (alu.cy) alu.inc(z[i]); else break;                // adc(1)
    alu.cy=cx|cy; for (i=n2-1;i>=0;i--) if (alu.cy) alu.inc(z[i]); else break;  // adc(1) if +=cx*(y0+y1)<<n2 or +=cy*(x0+x1)<<n2 overflowed
    delete[] q;
    #undef _add
    #undef _sub
    }
//---------------------------------------------------------------------------
void arbnum::mul_karatsuba(const arbnum &x,const arbnum &y)
    {
    // O(3*(N)^log2(3)) ~ O(3*(N^1.585))
    // Karatsuba multiplication
    int s=x.sig*y.sig;
    arbnum a,b; a=x; b=y; a.sig=+1; b.sig=+1;
    int i,n;
    for (n=1;(n<a.siz)||(n<b.siz);n<<=1);
    a._realloc(n);
    b._realloc(n);
    _alloc(n+n); for (i=0;i<siz;i++) dat[i]=0;
    _mul_karatsuba(dat,a.dat,b.dat,n);
    bits=siz<<5;
    sig=s;
    exp=a.exp+b.exp+((siz-a.siz-b.siz)<<5)+1;
//  _normalize();
    }
//---------------------------------------------------------------------------
  • 没有模数
  • 正如您所见,您需要+,-具有可变位宽的操作,两者都被编码为#define,因此不需要其他函数调用...
  • 它使用32bit ALU in x86 C++作为块来构建可变位宽度算术
  • 结果位于this对象
  • _mul_karatsuba只是内部递归函数
  • mul_karatsuba是主要的api ...

数字代表:

// dat is MSDW first ... LSDW last
DWORD *dat; int siz,exp,sig,bits;
  • dat[siz]是mantisa LSDW意味着最不重要的DWORD
  • exp是dat [0]
  • 的MSB的指数
  • mantisa中存在第一个非零位!!!

    // |-----|---------------------------|---------------|------|
    // | sig | MSB      mantisa      LSB |   exponent    | bits |
    // |-----|---------------------------|---------------|------|
    // | +1  | 0.(0      ...          0) | 2^0           |   0  | +zero
    // | -1  | 0.(0      ...          0) | 2^0           |   0  | -zero
    // |-----|---------------------------|---------------|------|
    // | +1  | 1.(dat[0] ... dat[siz-1]) | 2^exp         |   n  | +number
    // | -1  | 1.(dat[0] ... dat[siz-1]) | 2^exp         |   n  | -number
    // |-----|---------------------------|---------------|------|
    // | +1  | 1.0                       | 2^+0x7FFFFFFE |   1  | +infinity
    // | -1  | 1.0                       | 2^+0x7FFFFFFE |   1  | -infinity
    // |-----|---------------------------|---------------|------|