一个程序员与素数的故事
素数定义
素数:只能被1和本身整除的大于1的自然数;
从前有一座山,山里有一个村,村里有个未来的程序员,叫jiese;他很模糊的记得小学的时候,数学老师貌似给过他这个概念,小学的他傻傻的,成绩平平,智商也不高,这么不常用的概念早就被他忘得很彻底,就像忘记了什么时候学会站着撒尿忘得一样彻底,可是他万万没有想到素数看似不起眼,貌似毫无作用的东西,今后仍会与他纠缠;
当他考上大学的第一学期C语言课堂上,老师居然要他设计程序计算出100以内的素数;当时云里雾里的勉强的写出了这个程序:
程序1
//判断n是否为素数
bool IsPrime(int n)
{
int i = 2;
for (; i < n ; i++)
{
if ( 0 == n%i ) return false;
}
if (n > 1)
{
return true;
}
}
//输出<=n的素数
void PrintPrimes(int n)
{
for (int i = 2; i<= n; i++)
{
if (IsPrime(i))
{
printf("%d\n",i);
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
PrintPrimes(100);
return 0;
}
他当时费了九牛二虎之力写出了这个程序后,内心无比鸡动,还时不时得瑟下;那开心的劲,跟心里暗恋很久的“娟”答应做他女盆友似得;但是当时还是觉的中国的教育存在很大的问题,没事整些这样没意义的题目,高中应试教育,没想到大学来了还这样,谭浩强的教材也有求素数的题目(当时就是谭浩强的书做教材)!哎,悲哉。
可是他没想到当他大四时,拿起《编程珠玑》时,第一讲“性能监视工具”要求素数!今天的他可不比当年啊,毕竟已经有三年的编程学习了,积累了些东西!看到这个问题就立马能够写出“程序1”;可是他左想右想,好像还少点什么,这个程序效率可以再提高,毕竟这章主讲的是性能监视工具;由此而知这个程序可以优化;
那么这个算法要怎么样才能优化呢?想了一会儿,他忍不住了,不愿再继续想下去,接着《编程珠玑》往下看,发现,原来真的可以优化;国外大神写的书果然不一样,为了突出使用“性能监视工具”写了6个不同性能的求素数的程序;程序1算法效率是最差的。
有一个效率较高的程序
素数的基本定理
////素数基本定理:每个大于1的正整数都可以写成素数的乘积,并且这种乘积的形式是唯一的。
// 那么 自然数n>1,若n为非素数
// 则必然可以找到n的因数m1,m2 使得n == m1*m2 (m1>1 && m1<n && m2>1 && m2<n且m1,m2都为自然数) ,m1能整除n;
// 不妨设m1 <= m2,则m1*m1<=n;
// 故,当在循环找因数时,若i*i>n时都没有因数,那么该数为素数;
//根据基本定理判断素数的算法
bool IsPrime2(int n)
{
int i = 2;
for (; i*i <= n ; i++)
{
if ( 0 == n%i ) return false;
}
if (n > 1)
{
return true;
}
}
当时,jiese看到这个算法时,傻了眼,擦,还可以i*i呀,为什么可以这样?这样一个问题让他想了许久,不过凭他的智商估计也想不出为什么可以这样,不过这也不怪他,素数固有的性质和定理他都不知道,怎么可能想的明白!他虽然不太聪明,但是很明显这个问题跟素数的性质有关;于是开始,google,百度寻求答案;
所幸的是他不仅的到了答案,还有意外收获;很多年前,也就是70年代的时候,有几个数学家,提出一种编码方式,这种方法可以把通讯双方的约定公开,然而却很难破译密码,这种奇蹟般的密码就与素数有关。RSA就是这个编码方式;也就是那个与密钥和公钥有关的一个算法;
RSA算法
RSA提出后,三位发明家曾经公布了一条密码,悬赏100美元破译,他们预言,人们至少需要20000年,才能破译,即使计算机性能提高百倍,也需要200年。但只过了不到18年,这个密码就被人破译这个密码如此快的破解;
是因为全世界二十多个国家的六百多位工作者自发联合起来,利用计算机网络,同时进行因式分解,并不断交流信息,汇总计算结果,用了不到一年的时间,就将129位的N分解成64位和65位的两个素数的积。
计算机网络将分解效率提高了近万倍,这是发明者当初没有预想到的。但是,如果提高位数到200或300位,工作量将会大的不可思议,即使计算机技术有重大突破,破译也几乎不可能。
Jiese很想知道这究竟是怎样一种编码方式,居然这么吊;于是他硬着头皮去学习RSA的原理;真是费了九十牛二十虎之力才弄懂了RSA是怎么回事:
RSA:
B要发送消息给A,但是网络上的消息可以被别人抓包截获,那么B和A直接的消息就变得赤裸裸了,那怎么办,两人赤裸裸的多痛苦,那怎么办呢?
为B发送的消息内容加密,然后A获得消息之后再解密,来获得内容,其他获得消息但是解密不了的人,获得了消息也是枉然的!
A有一个公钥(N,e),所有人都可以知道的,当然B也知道;
A还有一个私钥(N,d)只有A知己知道。(其中N,e,d就是RSA算法算出的)
B通过一个众所周知的加密算法,将消息数据m,以及A给出的公钥e,通过公式 将m加密为c, 然后将c发送给B;
A获得c后利用只有知己知道的密钥d,通过公式 解密;
要是小黑获得了c,要想解密就要获得密钥d,但是要获得d可不是一件简单的事,最简单的方法就是将N分解,但至今为止还没有人找到一个多项式时间的算法来分解一个大的整数的因子,至今为止也没有人能够证明对N进行因数分解是唯一的从c导出n的方法,但今天还没有找到比它更简单的方法。因此今天一般认为只要N足够大,那么黑客就没有办法了,要是用穷举法暴力破解的话计算机要算很久很久很久很久才能算到。
Jiese知道是怎么回事之后也就没再纠缠下去,没去弄明白为什么这样做就能解密之类的问题,因为他已经头痛了,自己数学基础不扎实,又没有学过数论,要纠结下去估计要秃顶了。
Jiese费了九十牛二十虎之力,弄懂这些之后无限感慨;
1) 曾经听人家说,“数学对编程很重要,要想让自己在程序员的路上走得更远,必须学好数学”;Jiese总觉得说这话的人在装B,学了这么久的程序也不怎么正儿八经的用过数学知识,今天才领悟到不是别人在装B,只是自己没达到人家的水平,没能理解别人的话;要是Jiese学了3D,学了OpenGL的话,他一定会疯掉,里面有很多线性代数的知识很多高数、几何的知识,但是他这些课都打酱油了,他肯定会后悔死
2) 算法往往是针对某事物,抓住事物的特新,和一些规律,有时候可以让算法更高效;
3) 谭浩强没有他想的那么脑残,那么无聊;让我们计算素数估计是想让我们打好基础。
4)编程的路自己才走了一点点,不知道何时能从菜鸟变大神;大神,可是jiese一直以来可遇不可求的,但又梦寐以求的,
参考资料:
模反元素:http://zh.wikipedia.org/wiki/%E6%A8%A1%E5%8F%8D%E5%85%83%E7%B4%A0
RSA:http://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95