是否可以在不循环整个表达链的情况下计算Factorial(x)mod m
((1 % m) * (2 %m) * (3 % m) * ... (x % m)) % m?
更准确地说,m
可以是1< = m
< = 10 ^ 7并且x
:1< = x
<米
答案 0 :(得分:1)
Factorial的快速算法很少
[注释]
N!
,您需要一份最多N
N,m
[edit1]挖掘32位C ++实现
//---------------------------------------------------------------------------
DWORD modmul(DWORD a,DWORD b,DWORD n)
{
DWORD _a,_b,_n;
_a=a;
_b=b;
_n=n;
asm {
mov eax,_a
mov ebx,_b
mul ebx // H(edx),L(eax) = eax * ebx
mov ebx,_n
div ebx // eax = H(edx),L(eax) / ebx
mov _a,edx // edx = H(edx),L(eax) % ebx
}
return _a;
}
//---------------------------------------------------------------------------
DWORD modfact0(DWORD n,DWORD m) // (n!) mod m (naive approach)
{
DWORD i,f;
for (f=1,i=2;i<=n;i++) f=modmul(f,i,m);
return f;
}
//---------------------------------------------------------------------------
DWORD modfact1(DWORD n,DWORD m) // (n!) mod m (mine fast approach)
{
if (n<=4)
{
if (n==4) return 24;
if (n==3) return 6;
if (n==2) return 2;
if (n==1) return 1;
if (n==0) return 1;
}
int N4,N2,p,i,j,e; DWORD c,pp;
N4=(n>>2)<<2;
N2=N4>>1;
c=modfact1(N2,m); c=modmul(c,c,m); // c=((2N)!)^2;
for (i=0;;i++) // c*= T2
{
p=primes_i32.dat[i];
if (!p) break;
if (p>N4) break;
for (e=0,j=N4;j;e+=j&1,j/=p);
if (e) // c*=p^e
{
if (p==2) c<<=e;
else for (pp=p;;)
{
if (int(e&1)) c=modmul(c,pp,m);
e>>=1; if (!e) break;
pp=modmul(pp,pp,m);
}
}
}
for (i=N4+1;i<=n;i++) c=modmul(c,i,m);
return c;
}
//---------------------------------------------------------------------------
素数:
DWORD primes_i32.dat[]
是预先计算的所有素数的排序(升序)列表,最多为n
结果如下:
[ 18.529 ms] slow modfact0(1000000,1299721) = 195641
[ 2.995 ms] fast modfact1(1000000,1299721) = 195641
[ 96.242 ms] slow modfact0(5000000,9999991) = 2812527
[ 13.305 ms] fast modfact1(5000000,9999991) = 2812527
1299721
是接近1000000的第一个素数我发现m
不是素数并且子结果达到零,那么你可以忽略其余的乘法到大规模加速...... 希望结果没有可比性......