中国剩余定理

原文

孙子定理是中国古代求解一次同余式组的方法,又称中国余数定理。一元线性同余方程组问题最早可见于中国南北朝时期(公元5世纪)的数学著作《孙子算经》卷下第二十六题,叫做“物不知数”问题,原文如下:

今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?
答曰:‘二十三’。
术曰:三三数之剩二,置一百四十;五五数之剩三,置六十三,七七数之剩二,置三十,并之。得二百三十三,以二百一十减之,即得。凡三三数之剩一,则置七十;五五数之剩一,则置二十一;七七数之剩一,则置十五;一百六以上以一百五减之即得。

翻译翻译就是:
一个整数除以3余2、除以5余3、除以7余2,求这个整数。
答案:23
解法:由于除以3余2,因此加上一个140;由于除以5余3,因此加上一个63;由于除以7余2,因此加上一个30;这三个数的和是140+63+30=233,再减去210,就得到了23了。
这么说吧,只要是除以3余了一个1,就加上一个70;只要是除以5余了一个1,就加上一个21;只要是除以7余了一个1,就加上一个15。然后累加。超过了106就减去105就行了。

古人的解法

具体解法分三步:(一个整数除以3余2、除以5余3、除以7余2,求这个整数)

  1. 找出三个数:从3和5的公倍数中找出除以7余1的最小数15,从3和7的公倍数中找出除以5余1 的最小数21,最后从5和7的公倍数中找出除以3余1的最小数70。
  2. 用15乘以2(2为最终结果除以7的余数),用21乘以3(3为最终结果除以5的余数),同理,用70乘以2(2为最终结果除以3的余数),然后把三个乘积相加(15x2+21x3+70x2)得到和233。
  3. 用233除以3,5,7三个数的最小公倍数105,得到余数23,即233%105=23。这个余数23就是符合条件的最小数。

解法分析

计算一个整数 x x x ,使得它满足除以3余2、除以5余3、除以7余2。

如果能够找到三个整数 x 1 , x 2 , x 3 x_1,x_2,x_3 x1x2x3 ,使得:

  • x 1 x_1 x1除以3余2、除以5余0、除以7余0;
  • x 2 x_2 x2除以3余0、除以5余3、除以7余0;
  • x 3 x_3 x3除以3余0、除以5余0、除以7余2;

那么令 x = x 1 + x 2 + x 3 x=x_1+x_2+x_3 x=x1+x2+x3 ,就很容易验证这时的 x x x 就满足除以3余2、除以5余3、除以7余2。
继续细分
如果能够找到三个整数 y 1 , y 2 , y 3 y_1,y_2,y_3 y1y2y3 ,使得:

  • y 1 y_1 y1除以3余1、除以5余0、除以7余0;
  • y 2 y_2 y2除以3余0、除以5余1、除以7余0;
  • y 3 y_3 y3除以3余0、除以5余0、除以7余1;

那么 x = x 1 + x 2 + x 3 = 2 y 1 + 3 y 2 + 2 y 3 x=x_1+x_2+x_3=2y_1 + 3y_2 + 2y_3 x=x1+x2+x3=2y1+3y2+2y3 ,就很容易验证这时的 x x x 就满足除以3余2、除以5余3、除以7余2。
若是求最小正整数 x x x 。那么只需将 x x x 除以3,5,7的最小公倍数,取余数就行。

最终问题: 如何解 y 1 , y 2 , y 3 y_1,y_2,y_3 y1y2y3 ,,,
以解 y 1 y_1 y1 为例,寻找整数 y 1 y_1 y1 使得 y 1 y_1 y1 除以3余1、除以5余0、除以7余0。
那么 y 1 y_1 y1一定是 5 × 7 = 35 5 \times 7=35 5×7=35 的倍数,假设 y 1 = 35 t y_1=35t y1=35t
那么就有 35 t ≡ 1   ( m o d    3 ) 35t \equiv 1 \ (\mod 3) 35t1 (mod3),而这时的 t t t 就是35模3的逆,即 t ≡ 3 5 − 1 ( m o d    3 ) t \equiv 35^{-1}(\mod 3) t351(mod3) ,记作 [ 3 5 − 1 ] 3 \left[35^{-1} \right]_3 [351]3
那么 y 1 = 35 × [ 3 5 − 1 ] 3 = 5 × 7 × [ ( 5 × 7 ) − 1 ] 3 = 70 y_1=35 \times \left[35^{-1} \right]_3=5 \times 7 \times \left[(5 \times 7)^{-1} \right]_3=70 y1=35×[351]3=5×7×[(5×7)1]3=70
同理:
y 2 = 3 × 7 × [ ( 3 × 7 ) − 1 ] 5 = 21 y_2=3 \times 7 \times \left[(3 \times 7)^{-1} \right]_5=21 y2=3×7×[(3×7)1]5=21
y 3 = 3 × 5 × [ ( 3 × 5 ) − 1 ] 7 = 15 y_3=3 \times 5 \times \left[(3 \times 5)^{-1} \right]_7=15 y3=3×5×[(3×5)1]7=15
那么便能解出 x x x,即 x = 2 y 1 + 3 y 2 + 2 y 3 = 140 + 63 + 30 = 233 x =2y_1 + 3y_2 + 2y_3=140+63+30=233 x=2y1+3y2+2y3=140+63+30=233
最终结果就等于233除以105(3,5,7的最小公倍数)取余数,233%105=23,所以23就是最终结果。

补充个知识点。例:
23
23%3=2,23%5=3,23%7=2(除数 3 5 7 的最小公倍数是105)
23+105=128
128%3=2,128%5=3,128%7=2
23+210=233
233%3=2,233%5=3,233%7=2
显然,当一组除数和一组余数固定的时候,
有N个数除以这一组除数得到一样的一组余数,而这N个数是等差数列,公差是这一组除数的最小公倍数

例题

一个整数除以2余1,除以3余2、除以5余4、除以7余4,求这个整数。

解例题

一个整数除以2余1,除以3余2、除以5余4、除以7余4,求这个整数。
解: 解: 解:
第一步,找出四个数。 3 , 5 , 7 的最小公倍数是 105 ,除以 2 余数是 1 ,找到第一个数 105 2 , 5 , 7 的最小公倍数是 70 ,除以 3 余数是 1 ,找到第二个数 70 2 , 3 , 7 的最小公倍数是 42 ,除以 5 余数是 2 ,继续往上找, 84 , 126 , 168 等,发现 126 除以 5 余数是 1 ,找到第三个数 126 2 , 3 , 5 的最小公倍数是 30 ,除以 7 余数是 2 ,继续往上找, 60 , 90 , 120 等,发现 120 除以 7 余数是 1 ,找到第四个数 120 第二步,将这四个数分别乘以和对应的余数数值并求和。 y = 1 × 105 + 2 × 70 + 4 × 126 + 4 × 120 = 1229 第三步,用 y 除以 2 , 3 , 5 , 7 的最小公倍数,余数就是最终结果。 1229 m o d    [ 2 , 3 , 5 , 7 ] = 1229 m o d    210 = 179 ,这个整数就是 179 第一步,找出四个数。 \\ 3,5,7的最小公倍数是105,除以2余数是1,找到第一个数105 \\ 2,5,7的最小公倍数是70,除以3余数是1,找到第二个数70 \\ 2,3,7的最小公倍数是42,除以5余数是2,继续往上找,84,126,168等,发现126除以5余数是1,找到第三个数126 \\ 2,3,5的最小公倍数是30,除以7余数是2,继续往上找,60,90,120等,发现120除以7余数是1,找到第四个数120 \\ 第二步,将这四个数分别乘以和对应的余数数值并求和。 \\ y = 1 \times 105 + 2 \times 70 + 4 \times 126 + 4 \times 120=1229 \\ 第三步,用y除以2,3,5,7的最小公倍数,余数就是最终结果。 \\ 1229 \mod \left[ 2,3,5,7 \right]=1229 \mod 210=179,这个整数就是179 第一步,找出四个数。357的最小公倍数是105,除以2余数是1,找到第一个数105257的最小公倍数是70,除以3余数是1,找到第二个数70237的最小公倍数是42,除以5余数是2,继续往上找,84126168等,发现126除以5余数是1,找到第三个数126235的最小公倍数是30,除以7余数是2,继续往上找,6090120等,发现120除以7余数是1,找到第四个数120第二步,将这四个数分别乘以和对应的余数数值并求和。y=1×105+2×70+4×126+4×120=1229第三步,用y除以2,3,5,7的最小公倍数,余数就是最终结果。1229mod[2,3,5,7]=1229mod210=179,这个整数就是179

一元线性同余方程组

( 孙子算经中的方程 ) : { x ≡ 2   ( m o d    3 ) x ≡ 3   ( m o d    5 ) x ≡ 2   ( m o d    7 ) ( 例题方程 ) : { x ≡ 1   ( m o d    2 ) x ≡ 2   ( m o d    3 ) x ≡ 4   ( m o d    5 ) x ≡ 4   ( m o d    7 ) \begin{aligned} (孙子算经中的方程): \left\{ \begin{array}{c} x \equiv 2 \ (\mod 3) \\ x \equiv 3 \ (\mod 5) \\ x \equiv 2 \ (\mod 7) \\ \end{array} \right. \qquad (例题方程): \left\{ \begin{array}{c} x \equiv 1 \ (\mod 2) \\ x \equiv 2 \ (\mod 3) \\ x \equiv 4 \ (\mod 5) \\ x \equiv 4 \ (\mod 7) \\ \end{array} \right. \end{aligned} (孙子算经中的方程): x2 (mod3)x3 (mod5)x2 (mod7)(例题方程): x1 (mod2)x2 (mod3)x4 (mod5)x4 (mod7)

无论是孙子算经中的问题还是给出的例题,都可以写成上述方程组。显然方程可以有多个解。

将中国剩余定理一般化,给出了以下的一元线性同余方程组:
( S ) : { x ≡ a 1   ( m o d    m 1 ) x ≡ a 2   ( m o d    m 2 ) ⋮ x ≡ a n   ( m o d    m n ) (S): \left\{ \begin{array}{c} x \equiv a_1 \ (\mod m_1) \\ x \equiv a_2 \ (\mod m_2) \\ \vdots \\ x \equiv a_n \ (\mod m_n) \\ \end{array} \right. (S): xa1 (modm1)xa2 (modm2)xan (modmn)
中国剩余定理说明:假设整数m1,m2, … ,mn两两互质,则对任意的整数:a1,a2, … ,an,方程组S有解,并且通解可以用如下方式构造得到:

M = m 1 × m 2 × ⋯ × m n = ∏ i = n 10 m i M=m_1 \times m_2 \times \cdots \times m_n =\prod_{i=n}^{10}m_i M=m1×m2××mn=i=n10mi 是整数m1,m2, … ,mn的乘积,并设 M i = M / m i M_i=M/m_i Mi=M/mi M i M_i Mi是除了mi以外的n-1个整数的乘积。
t i ≡ M i − 1 ( m o d    m i ) t_i \equiv M^{-1}_i(\mod m_i) tiMi1(modmi) 。( t i t_i ti M i M_i Mi m i m_i mi意义下的逆元, M i t i ≡ 1 ( m o d    m i ) M_it_i \equiv 1(\mod m_i) Miti1(modmi)
方程组S的通解形式为: x = a 1 t 1 M 1 + a 2 t 2 M 2 + ⋯ + a n t n M n + k M = ∑ i = 1 n a i t i M i + k M , k 属于整数 x=a_1t_1M_1+a_2t_2M_2+ \cdots +a_nt_nM_n+kM=\displaystyle \sum_{i=1}^{n}{a_it_iM_i}+kM,k属于整数 x=a1t1M1+a2t2M2++antnMn+kM=i=1naitiMi+kMk属于整数
在模 M M M的意义下,方程组 ( S ) (S) (S)只有一个解: x = ( ∑ i = 1 n a i t i M i ) m o d      M x=\bigg(\displaystyle \sum_{i=1}^{n}{a_it_iM_i}\bigg) \mod \ M x=(i=1naitiMi)mod M

代码

用剩余定理的方式来解题

from functools import reduce
chu_num = [2, 3, 5, 7]
yu_num = [1, 2, 4, 4]
# # 三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2)
# chu_num = [3, 5, 7]
# yu_num = [2, 3, 2]

M = reduce(lambda x, y: x * y, chu_num) # 将数组chu_num里的所有数字做累乘运算
y = 0
for i in range(len(chu_num)):
    inverse = M//chu_num[i] # 现在的 inverse 是最小公倍数
    j = 1
    base = M//chu_num[i]
    while inverse % chu_num[i] != 1:
        j += 1
        inverse = base * j
    #print(chu_num[i],yu_num[i] , j , base)
    y += yu_num[i]*inverse
print(y)
print(y%M)

解同余方程组

from functools import reduce
import gmpy2
chu_num = [2, 3, 5, 7]
yu_num = [1, 2, 4, 4]
# # 三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2)
# chu_num = [3, 5, 7]
# yu_num = [2, 3, 2]

M = reduce(lambda x, y: x * y, chu_num) # 将数组chu_num里的所有数字做累乘运算
y = 0
for i in range(len(chu_num)):
    Mi = M // chu_num[i]
    # g == gcd(a,b) and g == a*s + b*t
    g,s,t = gmpy2.gcdext(Mi,chu_num[i])
    ti = s % chu_num[i]
    #print(chu_num[i],yu_num[i] , ti , Mi)
    y += yu_num[i] * ti * Mi
print(y)
print(y % M)

两代码就只有最后一部分不一样而已,但print打印的结果都是一样的,而且代码1中的inverse等于代码2中的ti * Mi
直接对比两代码的 y+= 部分:
代码1:y = 1 x 105 + 2 x 70 + 4 x126 + 4 x 120 = 1229
代码2:y = 1 x 1 x 105 + 2 x 1 x 70 + 4 x 3 x 42 + 4 x 4 x 40 = 1229
方程的余数部分是一样的,ti就是在中国剩余定理里,用最小公倍数找余数等于1时需要乘的倍数,Mi就是那个最小公倍数

补充

上文给的题目,除数都是两两互质的。所以在找它们的最小公倍数的时候,直接乘就行。但下面的例子就不能用同样的方法,它们只是相邻两个互质,但不是两两互质。

# 这个例子若用上面的代码
# 若用代码1的找法,第一轮的while循环直接死循环,3x4x5x6x7=2520,显然去找2520除以2余1的数,无论往上翻多少倍都不可能招到
# 代码2结果错误
chu_num = [2, 3, 4, 5, 6, 7]
yu_num = [1, 2, 1, 4, 5, 4]

上文给出的两种解法,不适用于不互质的情况,需要换个方式。

import math
chu_num = [2, 3, 4, 5, 6, 7]
yu_num = [1, 2, 1, 4, 5, 4]
# 上面这个是389,下面这个是179
# chu_num = [2, 3, 5, 7]
# yu_num = [1, 2, 4, 4]

def lcm(arr): # 求一组数的最小公倍数。例arr=[6,9,12],返回36
    k=1
    for i in arr:
        k=math.lcm(k,i)
    return k

num = 1
arr = []        # 这个数组是存储已经除过的数组(2-49之间的)
ind = 0
while ind < len(chu_num):     
    if num%chu_num[ind]==yu_num[ind]:    	# 判断余数是否相等
        arr.append(chu_num[ind])            # 相等就将除数存入数组
        ind += 1                            # 下标+1,继续判断下一个
    else:
        num += lcm(arr)          #如果余数不等的话,当前的数字=自身+数组的最小公倍数

print(num)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值