0

我试图估计将两个大位数以某个大素数为模相乘所需的时间。我的计算能力仅限于加法、乘法和存储 32 位数字。

由于这个原因,我想使用Karatsuba 算法,因为乘法被简化为一位数运算。然而,该算法不包含模约简。

我的另一个想法是使用蒙哥马利减少,但鉴于我的计算限制,我不确定这将如何执行。

你会建议我使用哪种算法?

4

1 回答 1

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因此不需要另一个函数调用......
  • 它使用x86 C++ 中的 32 位 ALU作为块来构建可变位宽算法
  • 结果在this对象中
  • _mul_karatsuba只是内部递归函数
  • mul_karatsuba是主要的api...

数字表示:

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

    // |-----|---------------------------|---------------|------|
    // | 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
    // |-----|---------------------------|---------------|------|
    
于 2015-03-09T15:17:12.577 回答