常用计算

在二进制浮点数内存中表示精确值很有难度。有些值无法准确地表示,而且如果通过反复计算来处理一个值,那么计算越频繁就越容易引入表示误差。math包含一个函数来计算一系列浮点数的和,它使用一种高效的算法来尽量减少这种误差。

新建math_fsum.py文件。

import math
values = [0.1] * 10
print('Input values:', values)
print('sum() : {:.20f}'.format(sum(values)))
s = 0.0
for i in values:
s += i
print('for-loop : {:.20f}'.format(s))
print('math.fsum() : {:.20f}'.format(math.fsum(values)))

以上代码输出结果为:

Input values: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
sum() : 0.99999999999999988898
for-loop : 0.99999999999999988898
math.fsum() : 1.00000000000000000000

以上代码,给定一个包含10个值的序列,每个值都等于0.1,这个序列总和的期望值为1.0.不过,由于0.1不能精确地表示为一个浮点值,所以会在总和中引入误差,除非用fsum()来计算。

factorial()常用于计算一系列对象的排列和组合数。一个正整数n的阶乘被递归定义为(n - 1)! * n,并在0 !== 1停止递归。

新建math_factorial.py文件。

import math
for i in [0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.1]:
try:
print('{:2.0f} {:6.0f}'.format(i, math.factorial(i)))
except ValueError as err:
print('Error computing factorial({}): {}'.format(i, err))

以上代码输出结果为:

0 1
1 1
2 2
3 6
4 24
5 120
Error computing factorial(6.1): factorial() only accepts integral values

以上代码,factorial()只能处理整数,不过它确实也接受float参数,只要这个参数可以转换为一个整数而不丢值。

gamma()类似于factorial(),不过它可以处理实数,而且值会下移一个数。

新建math_gamma.py文件。

import math
for i in [0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6]:
try:
print('{:2.1f} {:6.2f}'.format(i, math.gamma(i)))
except ValueError as err:
print('Error computing gamma({}): {}'.format(i, err))

以上代码输出结果为:

Error computing gamma(0): math domain error
1.1 0.95
2.2 1.10
3.3 2.68
4.4 10.14
5.5 52.34
6.6 344.70

以上代码由于0会导致开始值为负,所以这是不允许的。

lgamma()会返回输入值求gamma所得结果的绝对值的自然对数。

新建math_lgamma.py文件。

import math
for i in [0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6]:
try:
print('{:2.1f} {:.20f} {:.20f}'.format(
i,
math.lgamma(i),
math.log(math.gamma(i)),
))
except ValueError as err:
print('Error computing lgamma({}): {}'.format(i, err))

以上代码输出结果为:

Error computing lgamma(0): math domain error
1.1 -0.04987244125984036103 -0.04987244125983997245
2.2 0.09694746679063825923 0.09694746679063866168
3.3 0.98709857789473387513 0.98709857789473409717
4.4 2.31610349142485727469 2.31610349142485727469
5.5 3.95781396761871651080 3.95781396761871606671
6.6 5.84268005527463252236 5.84268005527463252236

以上代码,使用lgama()会比使用gamma()的结果单独计算对数更精确。

求模操作符(%)会计算一个除法表达式的余数(例如,5%2=1)。Python语言内置的这个操作符可以很好地处理整数,但是与很多其他浮点数运算类似,中间计算可能带来表示问题,从而进一步造成数据丢失。fmod()可以为浮点值提供一个更精确的实现。

新建math_fmod.py文件。

import math
print('{:^4} {:^4} {:^5} {:^5}'.format(
'x', 'y', '%', 'fmod'))
print('{:-^4} {:-^4} {:-^5} {:-^5}'.format(
'-', '-', '-', '-'))
INPUTS = [
(5, 2),
(5, -2),
(-5, 2),
]
for x, y in INPUTS:
print('{:4.1f} {:4.1f} {:5.2f} {:5.2f}'.format(
x,
y,
x % y,
math.fmod(x, y),
))

以上代码输出结果为:

x y % fmod
---- ---- ----- -----
5.0 2.0 1.00 1.00
5.0 -2.0 -1.00 1.00
-5.0 2.0 1.00 -1.00

以上代码,还有一点可能产生混淆,即fmod()计算模所使用的算法与%使用的算法也有所不同,所以结果的符号不同。

可以使用gcd()找出两个整数公约数中最大的整数————也就是最大公约数。

新建math_gcd.py文件。

import math
print(math.gcd(10, 8))
print(math.gcd(10, 0))
print(math.gcd(50, 225))
print(math.gcd(11, 9))
print(math.gcd(0, 0))

以上代码输出结果为:

2
10
25
1
0

以上代码,如果两个值都为0,则结果为0 。