求一个数的相反数算法(inverse to X modulo (1 << MOD))
(相反数的定义是:求Y 使(X * Y) mod (1 << MOD) == 1)
/*
*/param x X:inverse to X modulo (1 << MOD)
*/param mod MOD:inverse to X modulo (1 << MOD)
*/return the inverse number
*/
static unsigned long inverse (unsigned long x, int mod)
{
unsigned long mask = ((unsigned long) 1 << (mod - 1) << 1) - 1;
printf("mask=%lu,%x/n",mask,mask);
unsigned long rslt = 1;
int i;
for (i = 0; i < mod - 1; i++)
{
rslt = (rslt * x) & mask;
x = (x * x) & mask;
//printf("%d) rslt=%lu/tx=%lu/n",i,rslt,x);
}
return rslt;
}
一般的算法都是用Euclidean的逆步骤去解,但是这个算法不是。这个算的基本原理如下:
X为奇数时,存在0<i<mod,使得X^(2^i) % (2^mod) = 1
(这个我证明了一下,不难,我就不贴了)
即:X,X^2,X^4,X^8,X^16……X^2^(mod-1)里面一定有一个数,使X^(2^i) % (2^mod)=1
然后,X^(2^i-1)即为所求。
还有一个定理需要说明:X*Y % a =(X % a)*(Y % a) % a,
也就是:两个数相乘后取模,等于取模后相乘,再取模。这个也不用证明了吧。
注意算法里的mask=2^mod - 1 ,二进制表示为111111(mod个1)
ps.不知道为什么写成 1<<(mod-1)<<1 - 1,而不直接写成 1<<mod - 1
进行a & mask操作,相当于进行a%(2^mod)操作。
这是用&操作进行的优化。
现在看循环里的操作就比较简单了:
(先不看rslt)
循环里的X不断自乘,然后后取模,
所以X的值依次为
X(初始值)
附测试函数:
int main()
{
unsigned long x;
int mod;
scanf("%lu %d,",&x,&mod);
printf("%lu ",inverse(x,mod));
return 0;
}