3.3.2 标准库的数学模块
Python 的发明者吉多·范罗苏姆说:Python 有“自带电池”的理念,从它的庞大软件包复杂而又可靠的能力中可见端倪(英文:Python has a "batteries included" philosophy. This is best seen through the sophisticated and robust capabilities of its larger packages.参阅:https://en.wikipedia.org/wiki/Standard_library)。所谓“自带电池”就是指 Python 标准库(Python Standard Library,官方文档地址是 https://docs.python.org/3/library/index.html),标准库的有关程序在安装本地 Python 开发环境时已经随之安装好,与内置函数类似,也能“开箱即用”。
Python 标准库非常庞大,此处仅介绍与初等数学计算相关的模块(更多内容,参阅第11章11.3节)。
1. math 模块
标准库中的 math
模块主要提供初等数学中常用函数,官方文档地址是 https://docs.python.org/3/library/math.html。请在本地交互模式中,输入 import math
,然后敲回车键,如下所示:
>>> import math # (1)
>>>
输入注释(1)并敲回车键后,光标停在了下一行,且没有任何返回内容——关键是没有报错,这说明本地已经正确安装了 math
模块。注释(1)的作用是将标准库中的 math
模块引入到当前环境——标准库不是内置函数,其模块都必须用关键词 import
引入之后才能使用(参阅第11章11.1节)。
接着注释(1),继续执行如下操作:
代码语言:javascript复制>>> dir(math)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']
这里使用了内置函数 dir()
,它能够返回参数对象的属性和方法——在第2章2.4节初步接触了对象的“属性”和“方法”,更详细的内容请参阅第8章。对于 dir(math)
的返回结果,也可以理解为模块 math
里面提供的函数。不妨浏览一番这些函数名称,并与记忆中的初等数学常用函数对比,是不是觉得这里已经基本涵盖了常用的函数呢?
这些函数怎么用?以余弦函数 cos
为例,根据自学经验,应该先看一看这个函数的文档:
>>> help(math.cos)
注意上述写法,不能直接写 help(cos)
,因为函数 cos
是模块 math
的一员,注释(1)引入的是这个模块,当调用其中的函数时,必须借助模块的名称(可用图3-3-4所示帮助记忆和理解。这是调用模块内函数的一种方式,更多内容参阅第11章11.1节)。
图3-3-4 调用模块里的函数
执行上述语句,可以看到 math.cos
的帮助文档:
cos(x, /)
Return the cosine of x (measured in radians).
代码语言:javascript复制>>> alpha = 60 / 180 * math.pi # (2)
>>> math.cos(alpha) # (3)
0.5000000000000001
代码语言:javascript复制>>> math.pi
3.141592653589793
代码语言:javascript复制>>> round(math.cos(math.pi/4) math.log10(5) * math.exp(2), 2)
5.87
2. fractions 模块
在前面的代码演示中,注释(2)只能将分数计算为浮点数实现近似计算,如何才能实现精确地表示
呢?这就是标准库中的 fractions
模块所要解决的问题。
>>> import fractions # (4)
>>> a = fractions.Fraction(60, 180) # (5)
>>> a
Fraction(1, 3)
注释(4)引入模块 fractions
,注释(5)使用 fractions.Fraction()
创建分数——注意大小写,其参数中的第一个 60
是分数的分子,第二个 180
是分数的分母,即
。返回值是 Fraction(1, 3)
,表示分数
。由此可见,注释(5)创建分数的时候,会自动化简,以最简分数作为结果。
代码语言:javascript复制>>> 1 / 3 1 / 2
0.8333333333333333
这是用浮点数形式计算
的结果,现在可以这样做:
代码语言:javascript复制>>> b = fractions.Fraction(1, 2)
>>> a b
Fraction(5, 6)
如此就实现了分数的精确计算。
除了用注释(5)创建分数之外,还有其他的创建方式,此处不再赘述,请读者自行参考官方文档(https://docs.python.org/3/library/fractions.html)中的示例。下面要对注释(2)和(3)重新计算,用分数得到精确结果。
代码语言:javascript复制>>> alpha = fractions.Fraction('60/180') * math.pi # (6)
>>> fractions.Fraction(math.cos(alpha)).limit_denominator() # (7)
Fraction(1, 2)
先看结果,得到了
的精确结果
。不过,注释(6)中使用了另外一种创建分数的方法——参数形式与(5)不同(建议读者参阅官方文档示例)。注释(7)比较长,可以分为两部分,第一部分是 fractions.Fraction(math.cos(alpha))
,这其实是第三种创建分数的方法——参数是浮点数。
>>> fractions.Fraction(0.5)
Fraction(1, 2)
如注释(3)所示,math.cos(alpha)
的值是一个浮点数,再以它为参数,创建分数:
>>> fractions.Fraction(math.cos(alpha)) # (8)
Fraction(4503599627370497, 9007199254740992)
注意,math.cos(alpha)
的浮点数结果并非严格等于 0.5
(如注释(3)的返回值所示),因此在注释(8)中看到所得分数只能很接近于 Fraction(1, 2)
。为此,注释(7)调用了该对象的方法 limit_denominator()
,它的作用是返回最近似的分数——需要注意此方法的默认参数 max_denominator=1000000
,最近似的分数是以此分母计算,例如:
>>> fractions.Fraction('3.1415926535897932').limit_denominator(1000)
Fraction(355, 113)
>>> fractions.Fraction('3.1415926535897932').limit_denominator(100)
Fraction(311, 99)
>>> fractions.Fraction('3.1415926535897932').limit_denominator(10)
Fraction(22, 7)
当然,此处所创建的分数,也可以和浮点数、整数进行算术运算,或者作为函数的参数。
代码语言:javascript复制>>> a
Fraction(1, 3)
>>> a 2
Fraction(7, 3)
>>> a 0.5
0.8333333333333333
>>> a ** 2
Fraction(1, 9)
>>> pow(a, 3)
Fraction(1, 27)
>>> math.sin(a)
0.3271946967961522
问题来了,既然用分数对象能够精确计算,还要浮点数有什么用?有用!在 Python 中,运算 float
类型的对象要比运算 fractions.Fraction
类型的对象速度快,并且在一般情况下,浮点数运算的精度已经足够了。如果不是“一般情况”呢?就“鱼和熊掌不可兼得”,只能忍受“速度慢”了吗?也不是。Python 是一个开放的生态系统,除了标准库之外,还有更庞大的“第三方库”(参阅第11章),其中就有解决此问题的模块,比如 quicktions
—— “日光之下,并无新事”,倘若真的找不到满足需要的工具,那就是创新的机遇,一定要抓住。
针对本节内容,建议读者自己设计一些计算题进行练习——可以帮助中小学生解题。
这里暂介绍标准库中与数学计算有关的两个模块,在后续学习中还会遇到其他模块,第11章就此有专门介绍。
★自学建议 本节的学习中,使用了“帮助文档”和“官方文档”,这些文档是关于编程语言的最权威资料。但是,如何使用这些文档,是一个需要探讨的问题。以下是我的个人经验,供读者参考:
- 将文档当做《新华字典》那样的工具,有问题时去查询。一般地,语文学科的主要学习资料是课本,字典是必不可少的辅助学习的工具。但很少有人用《新华字典》来学习语文。有人号称“看文档就能掌握编程语言”,他一定是聪明人。
- 如果文档的原初语言是英文,尽可能看英文的文档(虽然有的文档翻译为中文了,但有的翻译并没有体现本意)。在第1章1.6节的【自学建议】中已经就本书引用英文文档的问题给予了解释说明,这里再次强调,旨在避免读者误解。凡是有志于自学,并以成为某领域翘楚为目标者,均不会畏惧各类文档中的英文。
在本书后续内容,我会经常提醒读者查看文档,根据以往经验,会有的学习者对此破不耐烦——曾有学习者在我的课程中对这种建议给予了“狂喷”。但我不会由于他的不满而改变此风格,真正有追求的读者能理解我的建议和要求。”