中国剩余定理编程实现

来源:互联网 发布:幽游白书 知乎 编辑:程序博客网 时间:2024/05/03 03:45

主要内容: 本文主要论述了中国剩余定理的背景,由来,离散数学证明方法,编程算法解决以及一些简单的应用,文章阐述了中国剩余定理的由来,介绍了他的几种解法.包括他的中国剩余定理研究,研究中国剩余定理的历史发展及在现代数论中的作用(历史、中国古代算法、现代解析方法、编程等)以及中国剩余定理在计算机科学上的其他的应用。

  中国剩余定理的简介以及形成

在我国古代劳动人民中,长期流传着“隔墙算”、“剪管术”、“秦王暗点兵”等数学游戏。有一首“孙子歌”,甚至远渡重洋,输入日本:“三人同行七十稀,五树梅花廿一枝,七子团圆正半月,除百零五便得知。” 这些饶有趣味的数学游戏,以各种不同形式,介绍世界闻名的“孙子问题”的解法,通俗地反映了中国古代数学一项卓越的成就。“孙子问题”在现代数论中是一个一次同余问题,它最早出现在我国公元四世纪的数学著作《孙子算经》中。《孙子算经》是算经十书之一,又作《孙子算术》。现有传本《孙子算经》分上、中、下共3卷。该书作者和确切成书年代均无法考证,大约成书于公元400年前后。中国古代求解一次同余式组(见同余)的方法。是数论中一个重要定理。又称中国剩余定理。 

一千多年前的《孙子算经》中,有这样一道算术题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”按照今天的话来说:一个数除以三余二,除以五余三,除以七余二,求这个数。《孙子算经》给出了一个非常有效的巧妙解法。术曰:“三、三数之剩二,置一百四十;五、五数之剩三,置六十三;七、七数之剩二,置三十,并之,得二百三十三。以二百一十减之,即得。凡三、三数之剩一,则置七十;五、五数之剩一,则置二十一;七、七数之剩一,则置十五。一百六以上,一百五减之,即得。

秦九韶从孙子定理中推广了“孙子问题”的解法形成了“中国剩余定理”。 秦九韶(秦九韶,字道古,生活于南宋时期,自幼喜好数学,经过长期积累和苦心钻研,干公元1247年写成《数书九章》。这部中世纪的数学杰作,在许多方面都有创造,其中求解一次同余组的“大衍求一术”和求高次方程数值解的“正负开方术”,更是具有世界意义的成就。秦九韶在《数书九章》中明确地系统地叙述了求解一次同余组的一般计算步骤。秦的方法,正是前述的剩余定理。)提出了乘率、定数、衍母、衍数等一系列数学概念,并详细叙述了“大衍求一术”的完整过程。直到此时,由《孙子算经》“物不知数”题开创的一次同余式问题,才真正得到了一个普遍的解法,才真正上升到了“中国剩余定理”的高度。  这个故事中所说的韩信点兵的计算方法,当时欧洲的数学家们对中国古代数学毫无所知.德国数学家高斯(1777~1855)通过独立研究,于公元1801年出版的《算术探究》上发表了著名的高斯定理,我们把孙子的“物不知其数”问题的解法与高斯定理一对照,不难看出:高斯定理实质上就是孙子解法的推广. 公元1852年,英国基督教士伟烈亚力将《孙子算经》中的“物不知其数”问题的解法传到欧洲。公元1874年,马蒂生指出:孙子的解法完全符合高斯的定理。而此时,高斯定理已比《孙子算经》中的“物不知其数”问题的解法晚一千五百多年.从此,在西文的数学史上将“物不知其数”问题称为“中国剩余定理”或“孙子定理”. 

 

 中国古代算法

中国剩余定理的古代算法实际上是,首先利用秦九韶发明的大衍求一术求出5和7的最小公倍数35的倍数中除以3余数为1的最小一个70(这个称为35相对于3的数论倒数),3和7的最小公倍数21相对于5的数论倒数21,3和5的最小公倍数15相对于7的数论倒数15。然后70X2+21X3+15X2=233

233便是可能的解之一。它加减3、5、7的最小公倍数105的若干倍仍然是解,因此最小的解为233除以105的余数23。

附注:这个解法并非最简,因为实际上35就符合除3余2的特性,所以最小解是:35X1+21X3+15X2-3X5X7=128-105=23 最小解加上105的正整数倍都是解。

但是中国古代的算法存在着许多的局限性,例如: 

(1)没有把解法总结成文,致使后人研究多凭猜测;

(2)模数仅限于两两互质的正整数,未涉及一般情况; 

(3)未能进一步探究同余式(组)有解的条件等理论问题

现代的解析算法

其实中国剩余定理额可以抽象成现代的数学问题。为了比较清除的了解“中国剩余定理”,我们可以引进课本中对于同余的定义:

若两个整数,b被同一个大于1的的整数m除有相同的余数,那么a,b模m同余(符号不好打,就不写了)

一次同余方程的求解的一般步骤:

所以 :


4   计算机编程来解决同余方程问题:

㈠算法思路

算法用到了C语言结构体的概念,定义一个结构体数组变量,里面定义了:除数:divisor,余数:remainder

范围最大值,最小值:MAX_NUM, MIN_NUM;,

最大公约数:gcd_max。循环变量:i,j。

步骤:

①首先我们要计算同余方程中的除数的乘积,因为同于方程的除数互素,所以利用一个for循环计算出。

然后利用双重for循环计算如果j!=i,则,否则跳出循环

③计算%T[i].divisor

④计算*

⑤结果的最小值为sum%m

C语言代码:

//中国剩余定理#include <stdio.h>struct node {int divisor;//表示除数int  remainder;//表示余数}T[1000];//求最大公约数int gcd ( int n, int m){    return m ? gcd(m, n%m) : n;}int main( ){//MAX_NUM表示的是所求的解的范围的最大值,MIN_NUM表示所求的解的范围的最小值,//n表示的是同于方程的个数,m表示的是三个除数的乘积,gcd_max表示的是两个数的最大公约数,因为三个除数是互素的//所以gcd_max=1;    int i, j, n, t = 0,m = 1, sum = 0, gcd_max = 0, MAX_NUM, MIN_NUM;        printf("请输入有几个方程:\n");   //如上题韩信点兵。输入3    scanf("%d", &n);    printf("请输入每组数据(  余数 除数):\n"); // 3 2 5 4 7 6    for ( i = 0; i < n; i++)        scanf("%d%d",&T[i].remainder,&T[i].divisor );    printf("请输入所求值的值域:min max\n" );        scanf("%d%d",&MIN_NUM, &MAX_NUM);//求出三个除数的乘积m    for ( i = 0; i < n; i++) {    gcd_max = gcd (T[i].divisor, gcd_max);    m = m * T[i].divisor;    }    gcd_max *= m;//求mI    for ( i = 0; i < n; i++)     {   t = 0;m = 1; for ( j = 0; j < n; j++){if (j != i  ){t = gcd( T[j].divisor , t);m  = m * T[j].divisor;}}t = m * t;m = t;while (m % T[i].divisor != 1)m += t;sum += m * T[i].remainder;    }    printf("最小的值为:\n");    printf("%d\n",sum % gcd_max);    printf("在所求的值域内值:\n");if (sum >= MIN_NUM && sum <= MAX_NUM){sum-=gcd_max;while(sum>=MIN_NUM && sum<=MAX_NUM){ printf("%d   ",sum);sum += gcd_max;}}else{ printf("No Solution!\n");}    return 0;}


例如:求解上面提到的同余方程:


我们换一组方程进行验证:

例2:对于同余方程:


我们手工进行演算的值为:

这里m1=3, m2=4, m3=5,m=60.

      M1=5×4=20, M1b ≡1(mod 3), M1^(-1) =b=2.

      M2=3×5=15, M2b≡1(mod 4), M2^(-1)=b=3

      M3=3×4=12, M3b≡1(mod 5), M3^(-1)=b=3.

      x≡2×1×20+2×3×15+3×3×12≡238≡58(mod 60).

      所以x=60k+58

编程实现:


通过以上的几个同余方程的验证,这个C语言的程序应该是正确的。只是这个程序的数据都是素数,对于合数的编程还没有实现

中国剩余定理在其他方面的应用

中国剩余定理虽然是数论中的基本定理,但是在计算机密码学中有着重要的作用,例如在Rabin密码算法中用于解密运算,在课本中提到的RSA密码算法中,中国剩余定理一样可以用于RSA的解密算法,而且能够提高加密解密的速度,这无论对于计算机硬件还是软件都十分重要的可见中国剩余定理应用之广泛 

2 0