指数和对数
指数生长曲线在经济学、物理学和其他学科中经常出现。Python有一个内置的幂运算符(”**”),不过,如果需要将一个可调用函数作为另一个函数的参数,那么困难需要用到pow()。
新建math_pow.py文件。
import math
INPUTS = [
(2, 3),
(2.1, 3.2),
(1.0, 5),
(2.0, 0),
(2, float('nan')),
(9.0, 0.5),
(27.0, 1.0 / 3),
]
for x, y in INPUTS:
print('{:5.1f}**{:5.3f} = {:6.3f}'.format(x, y, math.pow(x, y)))
以上代码输出结果为:
2.0**3.000 = 8.000
2.1**3.200 = 10.742
1.0**5.000 = 1.000
2.0**0.000 = 1.000
2.0** nan = nan
9.0**0.500 = 3.000
27.0**0.333 = 3.000
以上代码,1的任意次幂总返回1.0,同样,任何值的指数为0.0时也总是返回1.0,。对于nan值(不是一个数),大多数运算都返回nan。如果指数小于1,pow()会计算一个根。
由于平方根被使用得非常频繁,所以有一个单独的函数来计算平方根。
新建math_sqrt.py文件。
import math
print(math.sqrt(9.0))
print(math.sqrt(3))
try:
print(math.sqrt(-1))
except ValueError as err:
print('Cannot compute sqrt(-1):', err)
以上代码输出结果为:
3.0
1.7320508075688772
Cannot compute sqrt(-1): math domain error
以上代码,计算负数的平方根需要用到复数,这不在math处理范围内。试图计算一个负值的平方根时,会导致一个ValueError。
对数函数查找满足条件x = b ** y 的y。默认log()计算自然对数(底数为e)。如果提供了第二个参数,则使用这个参数值作为底数。
新建math_log.py文件。
import math
print(math.log(8))
print(math.log(8, 2))
print(math.log(0.5, 2))
以上代码输出结果为:
2.0794415416798357
3.0
-1.0
以上代码,x小于1时,求对数会产生负数结果。
10g()有三个变形。在给定浮点数表示和取整误差的情况下,由10g(x,b)生成的计算值只有有限的精度(特别是对于某些底数)。10g10()完成10g(x,10)计算,但是会使用一种比1og()更精确的算法。
新建math_log10.py文件。
import math
print('{:2} {:^12} {:^10} {:^20} {:8}'.format(
'i', 'x', 'accurate', 'inaccurate', 'mismatch',
))
print('{:-^2} {:-^12} {:-^10} {:-^20} {:-^8}'.format(
'', '', '', '', '',
))
for i in range(0, 10):
x = math.pow(10, i)
accurate = math.log10(x)
inaccurate = math.log(x, 10)
match = '' if int(inaccurate) == i else ' * '
print('{:2d} {:12.1f} {:10.8f} {:20.18f} {:^5}'.format(
i, x, accurate, inaccurate, match,
))
以上代码输出结果为:
i x accurate inaccurate mismatch
-- ------------ ---------- -------------------- --------
0 1.0 0.00000000 0.000000000000000000
1 10.0 1.00000000 1.000000000000000000
2 100.0 2.00000000 2.000000000000000000
3 1000.0 3.00000000 2.999999999999999556 *
4 10000.0 4.00000000 4.000000000000000000
5 100000.0 5.00000000 5.000000000000000000
6 1000000.0 6.00000000 5.999999999999999112 *
7 10000000.0 7.00000000 7.000000000000000000
8 100000000.0 8.00000000 8.000000000000000000
9 1000000000.0 9.00000000 8.999999999999998224 *
以上代码,输出中末尾有*的行突出强调了不精确的值。
类似于log10(),log2()会完成等价于math.log(x, 2)的计算。
新建math_log2.py文件。
import math
print('{:>2} {:^5} {:^5}'.format(
'i', 'x', 'log2',
))
print('{:-^2} {:-^5} {:-^5}'.format(
'', '', '',
))
for i in range(0, 10):
x = math.pow(2, i)
result = math.log2(x)
print('{:2d} {:5.1f} {:5.1f}'.format(
i, x, result,
))
以上代码输出结果为:
i x log2
-- ----- -----
0 1.0 0.0
1 2.0 1.0
2 4.0 2.0
3 8.0 3.0
4 16.0 4.0
5 32.0 5.0
6 64.0 6.0
7 128.0 7.0
8 256.0 8.0
9 512.0 9.0
以上代码,取决于底层平台,这个内置的特殊用途函数能提供更好的性能和精度,因为它利用了针对底数2的特殊用途算法,而在更一般用途的函数中没有使用这些算法。
log1p()会计算Newton-Mercator序列(1+x的自然对数)。
新建math_log1p文件。
import math
x = 0.0000000000000000000000001
print('x :', x)
print('1 + x :', 1 + x)
print('log(1+x):', math.log(1 + x))
print('log1p(x):', math.log1p(x))
以上代码输出结果为:
x : 1e-25
1 + x : 1.0
log(1+x): 0.0
log1p(x): 1e-25
以上代码,对于非常接近0的x,log1p()会更为精确,因为它使用的算法可以补偿由初始加法带来的取整误差。
exp()会计算指数函数(e ** x)。
新建math_exp.py文件。
import math
x = 2
fmt = '{:.20f}'
print(fmt.format(math.e ** 2))
print(fmt.format(math.pow(math.e, 2)))
print(fmt.format(math.exp(2)))
以上代码输出结果为:
7.38905609893064951876
7.38905609893064951876
7.38905609893065040694
以上代码,类似于其他特殊函数,与等价的通用函数math.pow(math.e, x)相比,exp()使用的算法可以生成更精确的结果。
expm1()是log1p()的逆运算,会计算e ** x - 1 。
新建math_expm1.py文件。
import math
x = 0.0000000000000000000000001
print(x)
print(math.exp(x) - 1)
print(math.expm1(x))
以上代码输出结果为:
1e-25
0.0
1e-25
以上代码,类似于log1p(),x值很小时,如果单独完成减法,即可能会损失精度。