本节书摘来自华章计算机《从问题到程序:用Python学编程和计算》一书中的第2章,第2.3节,作者 裘宗燕,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
2.3 内置函数和数学函数包
算术运算符提供了最基本的算术计算功能,通过写出复杂的表达式,可以完成许多复杂的计算。另一方面,有些很常用的计算,虽然可以通过简单计算的组合完成,但如果语言能通过某种易用的方式提供这种功能,编程序的人们就更方便了。
Python语言里提供方便使用的复杂功能的概念称为函数,这个概念与数学里的函数概念有相似之处。每个函数有一个名字,可以在表达式(或后面的其他结构)里使用。Python语言提供了一组函数(称为内置函数或标准函数),可以在程序里直接用。Python还通过标准库的程序包提供了许多有用的函数。
本节首先简单介绍函数的概念和使用方法,介绍几个与数值计算有关的内置函数,而后介绍Python标准库的浮点数数学函数包,其中定义了一组常用数学函数,包括三角函数、对数函数、双曲函数等。
2.3.1 函数及其使用
在Python语言里,函数是一种可以通过调用而被执行的对象。一个函数有一个名字,在写出的函数名之后写一对圆括号,括号中写几个表达式,就构成了一个函数调用表达式,简称函数调用。前面出现过的例如type(1.4)、int(2.3**12)、complex(2.3, 3.5)都是函数调用表达式,其中的type、int、complex在这里作为函数名,写在圆括号里的表达式称为函数的实际参数,简称实参,多个实参之间用逗号分隔。为了更清晰地显示函数调用中不同的实参,人们一般在逗号之后加一个空格。
type(1.4)表示要求解释器执行以type为名字的函数,把表达式1.4的值送给它。该函数将完成一些计算,最后返回一个结果。在前面示例中,我们已经看到解释器输出了反映type计算结果的信息。调用int将返回一个整数对象,调用complex将返回一个复数对象。在下面讨论中,通常把“以type为名字的函数”直接说成“函数type”,把“调用以type为名字的函数”说成“调用函数type”或者“调用type”。
函数调用是一种基本表达式,求值这种表达式就是要求执行相应函数,以函数执行的结果对象作为表达式的值,这样得到的值称为函数的返回值。
上面提到的几个函数都是Python语言内部定义的,默认地可以直接使用,因此它们都是内置函数。下面将看到,程序里还可以使用Python标准库程序包里定义的函数。2.9节将简单介绍如何自己定义有用的函数,后面有更多讨论。
2.3.2 处理数值的内置函数
Python语言提供了一组内置函数,它们的完整介绍参看附录B。现在介绍其中几个与数值计算有关的函数,可以用在表达式里描述数的计算。
函数abs的实参可以是值为整数、浮点数或复数的表达式,返回实参的绝对值:
>>> abs(-2.347**5)
71.2140111123765
>>> abs((2+3.5j)**5)
1064.4699683300428
复数的绝对值就是它的模,也就是复平面上这个复数表示的向量的长度。注意,如果实参是整数,abs就返回整型结果,对于浮点数或复数,它返回浮点型结果。
内置函数max和min分别求出其实参中的最大值和最小值。这两个函数的特殊之处在于它们可以有任意多个实参(至少两个)。例如:
>>> max(2, 3.57, 4.3, 3.6)
4.3
实参可以是任意复杂的表达式,只要求它们的值可以相互比较。如果只给min或max一个实参,解释器就会报错,说明所给实参不符合函数的要求。
round是另一个有用的函数,它求出浮点数的满足要求的近似值。这个函数有两种用法:round(number) 给出由浮点数number舍入得到的整数;另一种调用形式增加第二个指定舍入精度的整数参数,说明小数点后面保留的位数。例如:
>>> round(1.27**10)
11
>>> round(1.27**10, 4)
10.9153
最后一个是pow,调用pow(a, b)相当于ab。但pow还能以pow(a, b, c)的形式调用,相当于要求计算ab % c,但其算法更高效(注意,ab可能得到很大的值,而ab % c的值不会超过c,pow利用这一事实简化计算)。参与计算的整数很大时,这种调用形式就很有价值。在许多密码计算中需要这种函数。
2.3.3 数学函数包
数值计算中经常需要使用各种常用数学函数,日常使用的科学计算器都有这方面的功能键,编程语言自然也应该提供相应功能。因为常用数学函数很多,另一方面,许多程序并不需要用数学函数,因此Python没把常用数学函数包括在内置函数中,而是通过标准库里的一个程序包提供这些功能。
导入程序包
下载安装后的Python系统已经安装了标准库,其中包含一批程序包,提供了许多编程中经常需要的重要功能,数学函数包只是其中一个。每个程序包有一个名字,例如数学函数包的名字是math。如果想用数学函数包(或其他程序包),就必须首先将其导入。导入语句是我们接触的第一个非表达式的Python命令,这种命令称为语句。
导入语句有几种使用形式,后面有更详细的介绍,这里介绍两种常用形式。第一种形式要求把程序包里的全部功能导入,使这些功能都直接可用。例如,math包里定义了各种三角函数、指数和对数函数等,求弧度的正弦值和余弦值的函数名字分别为sin和cos。下面程序片段中导入math包并使用了它们:
>>> sin(3.14)
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
sin(3.14)
NameError: name 'sin' is not defined
>>> from math import *
>>> sin(3.14)
0.0015926529164868282
>>> cos(3.14)
-0.9999987317275395
上面第一行是在未导入math包的情况下调用sin函数,这时系统报错说“sin没有定义”。下一条是导入math包的命令,这个命令要求把math包的全部功能导入,使之在随后的计算中可用。最后两个表达式里使用了导入的函数sin和cos。
现在说明import语句的两种描述形式及其意义,以导入数学函数包为例,需要导入其他包时只需要在相应位置正确写出包的名字:
1)from math import *:要求导入数学包math里定义的所有功能,使它们都能在当前的环境中直接使用。
2)from math import sin, cos:选择性地导入数学包math里定义的函数sin和cos。采用这种描述形式,可以根据需要导入一个或多个函数,多个函数的名字之间用逗号分隔。在一个程序包里可能定义了很多东西,而实际程序中往往只需要用其中定义的几项功能。在很多情况下,选择性导入更可取。
math包
math包里定义了一批数学函数,包括:
1)指数和对数函数,如exp(n) 计算自然常数e的n次幂,log(x) 计算x的自然对数值。还可以用log函数可选的第二个参数指定对数的底,例如log(3.0, 2) 计算3.0的以2为底的对数值,log(11.3, 10) 计算实数11.3的以10为底的对数值。还有sqrt(x) 计算x的平方根。
2)三角函数和反三角函数,如上面用过的sin和cos,还有正切函数tan、反正弦函数asin、反余弦函数acos等。
3)双曲函数和反双曲函数,如sinh和cosh等。
4)其他有用函数,如从角度值计算出弧度值的radians,从弧度值算出角度值的degrees等。数学包里还定义了表示圆周率和自然对数的底的数学常数pi和e,导入后可以作为运算对象,直接用在表达式中。
更多函数、各函数的功能和使用时的写法等,在附录C有些介绍。
有了这些数学函数和常数,我们已经能很方便地实现科学计算器可以完成的所有计算了。例如,计算直径为12.4的圆球的体积:
>>> pi * 4.0/3.0 * (12.4/2)**3
998.305991926331
计算两个相邻边长度分别为11和17厘米,夹角34°的三角形的面积:
>>> 11.0 * 17.0 * sin(radians(34)) / 2.0
52.28453647451484
函数radians求出的值是浮点数,在表达式sin(radians(34))里用作sin的参数。由于函数调用也是表达式,自然可以作为另一个函数的参数。
Python还为复数提供了另一个数学包cmath,其中的函数与math类似,但处理的对象是复数。下面表达式验证了数学里最奇妙的一个公式:
>>> from cmath import exp
>>> exp(1.0j * pi) + 1
1.2246467991473532e-16j
这里做的也是近似计算,结果很接近0。