模取幂运算

    这本来是5.1前写的一个算法,可是一直没写好。因为数论这里有点东西没弄清楚,导致这个小问题搁置了很久(也因为还有其他事情要做,摊子铺的太大了)。最近做事情注意力不够集中,效率比较低,希望通过描述一下此算法,理理思路。
      规范起见,还是先描述一下该问题:求一个数的幂ab mod n (a,b和n是正整数)。描述完毕~
      其实硬算也是可以的,如果怕溢出,可以先求到一定范围,把结果存起来,再接着算…
      我这里还是把“硬算法”的具体方法描述一下吧:假设你的计算机只能取值到M,则当at<M时,                                 
             ab=at * ab-t
             ab mod n=(at * ab-t)mod n;
             由公式:(a * b) mod c=((a mod c)* b) mod c
             得  (at * ab-t)mod n=((at mod n)* ab-t) mod n;
      只要at<M,就不会有溢出了。
      好了,这种方法没有人会去用的。

     另外两种比较“理智”的方法(或者说是一种,因为原理都是相同的,只不过形式不一样),首先将 b转化为二进制数:(bk , bk-1, bk-2 …… b1, b0 ,)

 

          
方法
1
:(我以实例为例,因为说到底还是实例才能说清楚)

         a=5;b=22;c=50;(其实a c 取多少都和这里要说的没什么关系,只要看b就可以了) b的二进制表示为10110

        如果从右往左遍历该二进制序列,则第一位是0;若一个数的二进制表示中末尾为0,说明什么?对~~说明该数是能够被2整除的。那么        ab = aA*2  (b=2A)

    则ab mod n =( aA * aA ) mod n

    根据上面的公式: (a * b) mod c=((a mod c)* b) mod c

    得 ( aA * aA ) mod n = ((aA  mod n) * aA) mod n (一步一步写的我好辛苦)
        aA
是啥?对~~ aA 不就是10110 右移一位嘛,就是1011(右移一位等于原数除以2,这个不用我说了吧)。

    那么,就是从右往左遍历到第二位了。第二位是1,说明什么?对~~说明这个数不能被2整除 aA =aB+1(A=B+1),

    即 aA =aB * a

    那么,aA  mod n =((aB mod n) * a ) mod n

        aB是多少?对~~  其实 B不已经是偶数了嘛。

    用之前的方法类推,aB mod n = ((aC  mod n) * aC) mod n B=2C

    原式 aA  mod n =((aB mod n) * a ) mod n = (((aC  mod n) * aC ) mod n) * a ) mod c (注意区分大小写,ABC和原来的a,b,c不是一回事)

       aC 又是啥?以此类推。一直将二进制序列右移,反复嵌套,直到最后一位,就OK啦!

代码如下:

        int a,b,c;

        输入a,b,c的值

        int t=a;
    while (b>0)
    {
        if (b%2==1)
        {
            d=(d*t)%n;
        }
        b=b/2;
        t=(t*t)%n;
    }

             好累,明天再写方法2

点赞