zoukankan      html  css  js  c++  java
  • 快速幂与大数乘积取模

    快速幂:

    计算a^n%p的值,怎么算呢?直接算当然可能溢出。我们有一条引理:(a*b)%p=((a%p)*(b%p))%p.在这个引理上进行指数上的合并从而得到快速幂算法。

    具体地,有两种思路,一种是减小a值,以防溢出,一种是减小b值,加快计算。

    怎么减小a值?a=a%p,就把a的值降到了p以下。对b呢,我们发现,( a%p)*(a%p)=(a^2)%p,如果a^n次方n为偶数,a^(2m)%p = ((a^2)^m)%p,如果n为奇数,就先单独乘一个a,剩下的又是偶数了,这样n为偶数时就可以把n减小一半,从而降低了b的规模。

    大数乘取余:

    计算(a*b)%p怎么办?((a%p)*(b%p))%p还是会溢出。

    下面用到一种思想,神奇与上面的快速幂有异曲同工之妙,把b看成二进制表示。

    举个栗子:4*13%p,看成是4*1101(2)%p,其实表示的是4*(1*2^3+1*2^2+0*2^1+1*2^0)%p,那么我们在计算的时候就把b看成二进制,如果二进制最后一位是1,就说明这一位应该乘a取余,为零说明这一位不用乘a,从低位开始不断将b的二进制式右移,同时将a乘以2,等同于把基数平方,原因见上式。

    代码:

     1 #include <iostream>
     2 using namespace std;
     3 long long q_mod(long long a,long long n,long long p)
     4 {
     5     a = a%p;
     6     //首先降a的规模
     7     long long sum = 1;//记录结果
     8     while(n)
     9     {
    10         if(n&1)
    11         {
    12             sum = (sum*a)%p;//n为奇数时单独拿出来乘
    13         }
    14         a = (a*a)%p;//合并a降n的规模
    15         n /= 2;
    16     }
    17     return sum;
    18 }
    19 long long q_mul(long long a,long long b,long long p)
    20 {
    21     long long sum = 0;
    22     while(b)
    23     {
    24         if(b&1)//如果b的二进制末尾是零
    25         {
    26             (sum += a)%=p;//a要加上取余
    27         }
    28         (a <<= 1)%=p;//不断把a乘2相当于提高位数
    29         b >>= 1;//把b右移
    30     }
    31     return sum;
    32 }

    可以发现两者非常的相似,差别在于结果变量的初值和计算中加号和乘号的区别。

    参考文章:

    这几篇写得还是比较清晰的:

    六小聪,ACM算法:快速幂取模(详细),https://blog.csdn.net/dbc_121/article/details/77646508

    ygeloutingyu,大数乘法取模运算(二进制),https://www.cnblogs.com/geloutingyu/p/5886626.html

  • 相关阅读:
    List集合
    ArrayList_toArray
    Collection集合基础知识
    Array类的使用
    16.10
    16.9
    16.8
    16.7
    16.6
    16.5
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11257424.html
Copyright © 2011-2022 走看看