5.4.7 常用计算
在二进制浮点数内存中表示精确值很有难度。有些值无法准确地表示,而且如果通过反复计算来处理一个值,那么计算越频繁就越容易引入表示误差。math包含一个函数来计算一系列浮点数的和,它使用一种高效的算法来尽量减少这种误差。
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)))
给定一个包含10个值的序列,每个值都等于0.1,这个序列总和的期望值为1.0。不过由于0.1不能精确地表示为一个浮点值,所以会在总和中引入误差,除非用fsum()来计算。
运行结果:
factorial()长用于计算一系列对象的排列和组合数。一个正整数n的阶乘(表示为n!)被递归地定义为(n - 1)!*n,并在0!==1停止递归。
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))
factorial()只能处理整数,不过它确实也接受float参数,只要这个参数可以转换为一个整数而不丢值。
运行结果:
gamma()类似于factorial(),不过它可以处理实数,而且值会下移一个数(gamma等于(n - 1)!)。
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))
由于0会导致开始值为负,所以这是不允许的。
运行结果:
lgamma()会返回对输入值求gamma所得结果的绝对值的自然对数。
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))
使用lgamma()会比使用gamma()的结果单独计算对数更精确。
运行结果:
求模操作符(%)会计算一个除法表达式的余数(例如,5%2=1)。Python语言内置的这个操作符可以很好地处理整数,但是与很多其他浮点数运算类似,中间计算可能带来表示问题,从而进一步造成数据丢失。fmod()可以为浮点值提供一个更精确的实现。
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),
))
还有一点可能经常产生混淆,即fmod()计算模所使用的算法与%使用的算法也有所不同,所以结果的符号不同。
运行结果:
可使用gcd()找出两个整数公约数中最大的整数——也就是最大公约数。
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))
如果两个值都为0,则结果为0。
运行结果:
2
10
25
1
0