一、引言
Python里面有一个重要的求模运算符号“%”,作为一个小白,实验了好多次求模的运算,发现这个算法不同于一般的四则运算,其运算效率简直可以用神奇来形容。
例如以当今知道的最大质数——梅森素数为例,进行求模计算,速度快得惊人。当前知道的最大的梅森素数是第51个梅森素数,也是迄今为止知道的最大的素数。它的表示为:
2^82589933 – 1,
如果用十进制打开,这个数有24862048位,是2018年被证明为素数的。
在python中,如果直接计算这个数,一般的机器都是打不开的。如果做四则运算也是有可能死机的。但是神奇的是求模计算能够快速的出结果。
例如:
(2^82589933 – 1)%3=1
(2^82589933 – 1)%5=1
(2^82589933 – 1)%13=5
(2^82589933 – 1)%17=14

对于一个充满好奇心的小白来说,一定要探索一下其中的原理。于是先百度一下求模的基本知识,发现有如下的表述:
模运算在数论和程序设计中都有着广泛的应用,奇偶数的判别到素数的判别,从模幂运算到最大公约数的求法,从孙子问题到凯撒密码问题,无不充斥着模运算的身影。虽然很多数论教材上对模运算都有一定的介绍,但多数都是以纯理论为主,对于模运算在程序设计中的应用涉及不多。
取模运算(“Modulo Operation”)和取余运算(“Remainder Operation ”)两个概念有重叠的部分但又不完全一致。主要的区别在于对负整数进行除法运算时操作不同。取模主要是用于计算机术语中。取余则更多是数学概念。

求整数商: c=[a/b]
计算模: r=a-c*b
基本知识中,大量讲解数学求余和计算机求模的区别,为简化和理解。本部分只讨论计算机领域的求模运算。

二、取模运算

1.定义:取模运算:运算结果得到的是一个数除以另一个数的余数,即采用公式r=a-c*b,但是c的取值在数轴上取左边的整数解(如果b为正数,计算机的求模计算)。

2.举例:给定两个正整数:被除数 a 和除数 n,a modulo n (缩写为(一般这样写) a mod n)得到的是a/n 的余数。

3.但是当有负数加入到取模运算,就变得比较复杂了。在python中,如果b为正整数,则所有的r都为正(除0外),因为求整数的c是在数轴的左侧取b的整数解,也就是说a一定 大于c*b。如果b为负整数,则所有的r都为负(除0外),因为求整数的c是在数轴的右侧取b的整数解。

三、取模运算的规则

1.恒等式:
① (a mod n) mod n = a mod n
② 对所有的正数 x 有:nx mod n = 0
费马小定理:a^(p-1)≡1(mod p), where p is a prime,并且a不是p的倍数
也可以表示为: a^p≡a(mod p) (a为任意正整数,上式中a不能使p的倍数)
用python的符号%表示为: a^p%p=a%p, a为任意正整数,p为质数。

  1. 取模与四则运算的关系(除法除外,除法不同):

①加法:(a+b) mod c = [(a mod c) + (b mod c)] mod c
②减法:(a-b) mod c = [(a mod c) - (b mod c)] mod c
③乘法:ab mod c = [(a mod c)(b mod c)] mod c
④乘方:a^b mod c = [(a mod c)^b]mod c

  1. 其他一般定律
    ①结合律:加法结合律 ((a+b) % c + c) % c = (a + (b+c) % c) % c
    乘法结合律 ((ab) % c * c)% c = (a * (bc) % c) % c
    ②交换律:加法交换律 (a + b) % c = (b+a) % c
    乘法交换律 (a * b) % c = (b * a) % c
    ③分配律:((a +b)% c * c) % c = ((a * c) % c + (b * c) % c) % c
  2. 组合律的应用定理
    若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);
    若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);
    若a≡b (%p),c≡d (%p),
    则 (a + c) ≡ (b + d) (%p),
    (a - c) ≡ (b - d) (%p),
    (a * c) ≡ (b * d) (%p),
    (a / c) ≡ (b / d) (%p)
  3. 乘法逆元
    如果ax≡1 mod p,且gcd(a,p)=1(a,p 互质, gcd()函数为最大公因数), 则称a关于模p的乘法逆元为x。
    既然有ax≡1 mod p, 那么存在整数x、y解,使得ax-py=1,叫做x是a关于模p的乘法逆元。

四、回答开篇的梅森素数快速求模的问题
例:以最大的第51个梅森素数为例,
解法1采用费马小定理
((2^82589933)-1)%3
= ((2^82589933)%3-1%3) %3
= (((2(3-1)%3)int(82589933/2))%32%3-1%3) %3
= ((1^ int(82589933/2))%3
2%3-1%3)%3
= (1%3* 2%3-1%3)%3
= 1

解法2 采用一般的凑≡1(mod c)的方法
因为2^2≡1(mod 3)
所以2^(2* 42294966) ≡1(mod 3)
=> (2^82589933)%3 = (2^(2* 42294966)) %3*2%3 = 2%3
=> ((2^82589933)-1)%3 =(2%3-1%3)%3
= 1

五、同余关系在求余中的占比问题 (一个特殊问题的观念)

同余问题是求余问题中引申出来的重要的一个方面,也是中国余数定理(孙子定理)的重要分支。其中还有一个重要的口诀:“余同取余。和同加和,差同减差,公倍数作周期”。
例如:
① 余同:例:“一个数除以4余1,除以5余1,除以6余1”,因为余数都是1,则取1,公倍数作周期,则表示为:60N+1
② 和同:例:“一个数除以4余3,除以5余2,除以6余1”,因为4+3=5+2=6+1=7,则取7,公倍数做周期:则表示为60N+7
③ 差同:例:“一个数除以4余1,除以5余2,除以6余3”,因为4-1=5-2=6-3=3,则取3,公倍数做周期:则表示为60N-3

中国人总结的口诀清晰明了,但是有个问题就是往往中国人的总结的东西适用性不够全面。也就是说,同余关系的情况,很有可能只是求余中的少数特例,不具备成为更为普遍性的定理。为了验证这个问题,需要计算一下三种“同余关系”在求余中的情况占比。
还以上述例子的4,5,6,三个模为例。
在一个公倍数60的周期里面,总共的余数情况有60种,需要看看“余同”、“和同”、“差同”的各自占比情况。
从下表可知,余同的情况占比:
① 余同:占比 4/60=6.67%
② 和同:占比 2/60=3.33%
③ 差同:占比 4/60=6.67%
三种同的情况占比总共只有:10/60=16.67%
而其他的情况,占比:50/60=83.33%。

结论是:同余问题只占余数定理中的很少的情况

表. 模4,5,6的余数情况表

求一个合数的最大质因数 python python计算最大素数_模运算