void NR::mpdiv(Vec_O_UCHR &q, Vec_O_UCHR &r, Vec_I_UCHR &u, Vec_I_UCHR &v) { const int MACC=1; int i,is,mm; int n=u.size(); int m=v.size(); int p=r.size(); int n_min=MIN(m,p); if (m > n) nrerror("Divisor longer than dividend in mpdiv"); mm=m+MACC; Vec_UCHR s(mm),rr(mm),ss(mm+1),qq(n-m+1),t(n); mpinv(s,v); mpmul(rr,s,u); mpsad(ss,rr,1); mplsh(ss); mplsh(ss); mpmov(qq,ss); mpmov(q,qq); mpmul(t,qq,v); mplsh(t); mpsub(is,t,u,t); if (is != 0) nrerror("MACC too small in mpdiv"); for (i=0;i<n_min;i++) r[i]=t[i+n-m]; if (p>m) for (i=m;i<p;i++) r[i]=0; }
void NR::mpmul(Vec_O_UCHR &w, Vec_I_UCHR &u, Vec_I_UCHR &v) { const DP RX=256.0; int j,n_max,nn=1; DP cy,t; int n=u.size(); int m=v.size(); int p=w.size(); n_max=MAX(m,n); while (nn < n_max) nn <<= 1; nn <<= 1; Vec_DP a(0.0,nn),b(0.0,nn); for (j=0;j<n;j++) a[j]=u[j]; for (j=0;j<m;j++) b[j]=v[j]; realft(a,1); realft(b,1); b[0] *= a[0]; b[1] *= a[1]; for (j=2;j<nn;j+=2) { b[j]=(t=b[j])*a[j]-b[j+1]*a[j+1]; b[j+1]=t*a[j+1]+b[j+1]*a[j]; } realft(b,-1); cy=0.0; for (j=nn-1;j>=0;j--) { t=b[j]/(nn >> 1)+cy+0.5; cy=(unsigned long) (t/RX); b[j]=t-cy*RX; } if (cy >= RX) nrerror("cannot happen in mpmul"); for (j=0;j<p;j++) w[j]=0; w[0]=(unsigned char) cy; for (j=1;j<MIN(n+m,p);j++) w[j]=(unsigned char) b[j-1]; }
void NR::mpsqrt(Vec_O_UCHR &w, Vec_O_UCHR &u, Vec_I_UCHR &v) { const int MF=3; const DP BI=1.0/256.0; int i,ir,j,mm; DP fu,fv; int n=u.size(); int m=v.size(); Vec_UCHR r(2*n),x(n+m),s(2*n+m),t(3*n+m); mm=MIN(m,MF); fv=DP(v[mm-1]); for (j=mm-2;j>=0;j--) { fv *= BI; fv += v[j]; } fu=1.0/sqrt(fv); for (j=0;j<n;j++) { i=int(fu); u[j]=(unsigned char) i; fu=256.0*(fu-i); } for (;;) { mpmul(r,u,u); mplsh(r); mpmul(s,r,v); mplsh(s); mpneg(s); s[0] += (unsigned char) 3; mpsdv(s,s,2,ir); for (j=1;j<n-1;j++) { if (s[j] != 0) { mpmul(t,s,u); mplsh(t); mpmov(u,t); break; } } if (j<n-1) continue; mpmul(x,u,v); mplsh(x); mpmov(w,x); return; } }