【问题描述】
哥德巴赫在1742年给欧拉的信中提出了以下猜想:任一大于2的偶数都可写成两个素数之和。但是哥德巴赫自己无法证明它,于是就写信请赫赫有名的大数学家欧拉帮忙证明,但是一直到死,欧拉也无法证明。请编写程序验证1000以内的偶数符合哥德巴赫猜想。
输出结果:
4=2+2
6=3+3
8=3+5
10=3+7
12=5+7
……
992=73+919
994=3+991
996=5+991
998=7+991
【题前思考】
根据问题描述,填写表5-1-1。
表5-1-1 问题分析
【解题思路】
把一个数分成两个数的和可以表示成x=a+b,x就是要分解的数,其中a,b都是正整数,为了避免重复,规定a<=b。显然,a=1时,b=x-1;a=2时,b=x-2,以此类推就可以得到所有可能的分解式。按题目要求,a和b都是质数就算找到了一个分解,于是,这个问题的关键就是判断a和b都是质数。这样,在程序中就需要两次用到判断质数的代码,我们可以将判断质数的代码定义成函数,然后在程序中直接调用就可以了。
【程序代码】
【代码分析】
①:定义名为prime的函数用于判断一个数是否为质数,这个函数有一个形参(形式参数的简称)n,表示被判断的数,这行代码用自然语言翻译过来就是“定义函数prime,判断n是否为质数”。定义函数以关键字def开始,后面是空格分隔的函数名。函数名后圆括号括起来的是形参列表。形参列表由逗号分隔的若干个形参组成,最后程序行以冒号结束。这一行代码称为函数头,函数头下方缩进的语句就是被封装重用的代码,称为函数体,函数的功能就是由函数体实现的。在本例中函数体的作用就是判断n是否为质数。定义函数的语法结构如图5-1-1所示。
图5-1-1 定义函数的语法结构
②:表示将变量flag的值返回给调用prime函数的程序,同时中止prime函数的执行。在程序中使用一个函数称为调用,被调用的函数称为被调函数,return表示返回的意思,就是将被调函数的计算结果传回给调用者,同时中止被调函数的执行。从函数体的代码可以看出,在本例中当n的值是质数时返回True,反之返回False。
③:表示如果该模块被直接执行,而非用import命令导入则执行后面的代码。每个Python模块都有__name__属性,表示模块的名称。如果使用import命令导入模块,则模块的名称(__name__属性的值)为模块所在的文件名;如果模块被直接执行,则模块的名称(__name__属性的值)就是“__main__”。在本例中,模块所在的文件名为“哥德巴赫猜想.py”,如果在另一个程序中使用命令“import哥德巴赫猜想as module”导入,则module.__name__的值就为“哥德巴赫猜想”。如果在终端用命令“python哥德巴赫猜想.py”直接执行程序,__name__的值就是“__main__”。这就意味着,如果用import命令导入这个模块,if__name__=='__main__':后的代码不会被执行,而在终端直接用命令运行这个模块,if__name__=='__main__':后的代码会被执行。
④:将a分解成两个数:b和a-b,很明显b与a-b的和是a,此时如果这两个数都是质数就输出这两个数,完成了将a分解成两个质数的操作,就不再需要循环“for b in range(2,a//2+1)”,于是中止它(break)。表达式prime(b)and prime(a-b)用于判断b和a-b是否都是质数。prime(b)和prime(a-b)称为函数调用,此时参数b和a-b称为实参(实际参数的简称)。下面以a=12,b=3为例,展示函数调用和返回的过程。
将实参的值传递给形参,也就是将b的值3传递给形参n,如图5-1-2所示。
图5-1-2 实参值传递给形参
执行函数体中的代码。参数传递,相当于执行前为n赋值为3,如图5-1-3所示。
图5-1-3 执行函数体代码
将flag的值返回给调用者,替换表达式中的函数调用,如图5-1-4所示。
图5-1-4 返回值替换函数调用
与prime(a)的执行过程一样,prime(a-b)的值为False,在两个函数调用结束之后,原表达式prime(b)and prime(a-b)变成了True and False。
【优化提升】
以上代码中,if__name__=="__main__":后的代码使用了双重循环,为了让代码更好理解,我们可以把内层循环也封装成一个函数split( ),实现将一个数分解成两个质数的功能,代码如下:
【技术全貌】
在编程时,很多你想要的功能别人早就想到了,而且设计了非常高效的算法,封装成了函数,我们只需要调用这些函数就可以了。表5-1-2给出了Python中的常用内置函数。如果想要查询Python中更多的函数,请扫描二维码,阅读官网文档。
表5-1-2 内置函数表
续表