Python3标准库:math数学函数
1. math数学函数
1.1 特殊常量
很多数学运算依赖于⼀些特殊的常量。math包含有π(pi)、e、nan(不是⼀个数)和infinity(⽆穷⼤)的值。
import math
print(' π: {:.30f}'.format(math.pi))
print(' e: {:.30f}'.format(math.e))
print('nan: {:.30f}'.format(math.nan))
print('inf: {:.30f}'.format(math.inf))
π和e的精度仅受平台的浮点数C库限制。
1.2 测试异常值
浮点数计算可能导致两种类型的异常值。第⼀种是inf(⽆穷⼤),当⽤double存储⼀个浮点数,⽽该值会从⼀个具体很⼤绝对值的值上溢出时,就会出现这个异常值。
import math
print('{:^3} {:6} {:6} {:6}'.format(
'e', 'x', 'x**2', 'isinf'))
print('{:-^3} {:-^6} {:-^6} {:-^6}'.format(
'', '', '', ''))
for e in range(0, 201, 20):
x = 10.0 ** e
y = x * x
print('{:3d} {:<6g} {:<6g} {!s:6}'.format(
e, x, y, math.isinf(y),
))
当这个例⼦中的指数变得⾜够⼤时,x的平⽅⽆法再存放⼀个double中,这个值就会被记录为⽆穷⼤。
不过,并不是所有浮点数溢出都会导致inf值。具体地,⽤浮点值计算⼀个指数时,会产⽣OverflowError⽽不是保留inf结果。
x = 10.0 ** 200
print('x =', x)
print('x*x =', x * x)
print('x**2 =', end='')
try:
print(x ** 2)
except OverflowError as err:
print(err)
这种差异是由C和Python所⽤库中的实现差异造成的。
使⽤⽆穷⼤值的除法运算未定义。将⼀个数除以⽆穷⼤值的结果是nan(不是⼀个数)。
import math
x = (10.0 ** 200) * (10.0 ** 200)
y = x / x
print('x =', x)
print('isnan(x) =', math.isnan(x))
print('y = x / x =', x / x)
print('y == nan =', y == float('nan'))
print('isnan(y) =', math.isnan(y))
nan不等于任何值,甚⾄不等于其⾃⾝,所以要想检查nan,需要使⽤isnan()。
可以使⽤isfinite()检查其是普通的数还是特殊值inf或nan。
import math
for f in [0.0, 1.0, math.pi, math.e, math.inf, math.nan]:
print('{:5.2f} {!s}'.format(f, math.isfinite(f)))
如果是特殊值inf或nan,则isfinite()返回false,否则返回true。
1.3 ⽐较
涉及浮点值的⽐较容易出错,每⼀步计算都可能由于数值表⽰⽽引⼊误差,isclose()函数使⽤⼀种稳定的算法来尽可能减少这些误差,同时完成相对和绝对⽐较。所⽤的公式等价于:
abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
默认地,isclose()会完成相对⽐较,容差被设置为le-09,这表⽰两个值之差必须⼩于或等于le乘以a和b中较⼤的绝对值。向isclose()传⼊关键字参数rel_tol可以改变这个容差。在这个例⼦中,值之间的差距必须在10%以内。
import math
INPUTS = [
(1000, 900, 0.1),
(100, 90, 0.1),
(10, 9, 0.1),
(1, 0.9, 0.1),
(0.1, 0.09, 0.1),
]
print('{:^8} {:^8} {:^8} {:^8} {:^8} {:^8}'.format(
'a', 'b', 'rel_tol', 'abs(a-b)', 'tolerance', 'close')
)
print('{:-^8} {:-^8} {:-^8} {:-^8} {:-^8} {:-^8}'.format(
'-', '-', '-', '-', '-', '-'),
)
fmt = '{:8.2f} {:8.2f} {:8.2f} {:8.2f} {:8.2f} {!s:>8}'
for a, b, rel_tol in INPUTS:
close = math.isclose(a, b, rel_tol=rel_tol)
tolerance = rel_tol * max(abs(a), abs(b))
abs_diff = abs(a - b)
print(fmt.format(a, b, rel_tol, abs_diff, tolerance, close))
0.1和0.09之间的⽐较失败,因为误差表⽰0.1。
要使⽤⼀个固定或“绝对”容差,可以传⼊abs_tol⽽不是rel_tol。
import math
INPUTS = [
(1.0, 1.0 + 1e-07, 1e-08),
(1.0, 1.0 + 1e-08, 1e-08),
(1.0, 1.0 + 1e-09, 1e-08),
]
print('{:^8} {:^11} {:^8} {:^10} {:^8}'.format(
'a', 'b', 'abs_tol', 'abs(a-b)', 'close')
)
print('{:-^8} {:-^11} {:-^8} {:-^10} {:-^8}'.format(
'-', '-', '-', '-', '-'),
)
for a, b, abs_tol in INPUTS:
close = math.isclose(a, b, abs_tol=abs_tol)
abs_diff = abs(a - b)
print('{:8.2f} {:11} {:8} {:0.9f} {!s:>8}'.format(
a, b, abs_tol, abs_diff, close))
对于绝对容差,输⼊值之差必须⼩于给定的容差。
nan和inf是特殊情况。
import math
print('nan, nan:', math.isclose(math.nan, math.nan))
print('nan, 1.0:', math.isclose(math.nan, 1.0))
print('inf, inf:', math.isclose(math.inf, math.inf))
print('inf, 1.0:', math.isclose(math.inf, 1.0))
nan不接近任何值,包括它⾃⾝。inf只接近它⾃⾝。
1.4 将浮点值转换为整数
math模块中有3个函数⽤于将浮点值转换为整数。这3个函数分别采⽤不同的⽅法,并适⽤于不同的场合。
最简单的是trunc(),其会截断⼩数点后的数字,只留下构成这个值整数部分的有效数字。floor()将其输⼊转换为不⼤于它的最⼤整数,ceil() (上限)会⽣成按顺序排在这个输⼊值之后的最⼩整数。
import math
HEADINGS = ('i', 'int', 'trunk', 'floor', 'ceil')
print('{:^5} {:^5} {:^5} {:^5} {:^5}'.format(*HEADINGS))
print('{:-^5} {:-^5} {:-^5} {:-^5} {:-^5}'.format(
'', '', '', '', '',
))
fmt = '{:5.1f} {:5.1f} {:5.1f} {:5.1f} {:5.1f}'
TEST_VALUES = [
-1.5,
-0.8,
-0.5,
-0.2,
0,
0.2,
0.5,
0.8,
1,
]
for i in TEST_VALUES:
print(fmt.format(
i,
int(i),
math.floor(i),
))
trunc()等价于直接转换为int。
1.5 浮点值的其他表⽰
modf()取⼀个浮点数,并返回⼀个元组,其中包含这个输⼊值的⼩数和整数部分。import math
for i in range(6):
print('{}/2 = {}'.format(i, df(i / 2.0)))
返回值中的两个数字均为浮点数。
frexp()返回⼀个浮点数的尾数和指数,可以⽤这个函数创建值的⼀种更可移植的表⽰。import math
print('{:^7} {:^7} {:^7}'.format('x', 'm', 'e'))
print('{:-^7} {:-^7} {:-^7}'.format('', '', ''))
for x in [0.1, 0.5, 4.0]:
m, e = math.frexp(x)
print('{:7.2f} {:7.2f} {:7d}'.format(x, m, e))
frexp()使⽤公式x = m * 2**e,并返回值m和e。
ldexp()与frexp()正好相反。
import math
print('{:^7} {:^7} {:^7}'.format('m', 'e', 'x'))
print('{:-^7} {:-^7} {:-^7}'.format('', '', ''))
INPUTS = [
(0.8, -3),
(0.5, 0),
(0.5, 3),
]
for m, e in INPUTS:
x = math.ldexp(m, e)
print('{:7.2f} {:7d} {:7.2f}'.format(m, e, x))
ldexp()使⽤与frexp()相同的公式,取尾数和指数值作为参数,并返回⼀个浮点数。python trunc函数
1.6 正号和负号
⼀个数的绝对值就是不带正负号的本值。使⽤fabs()可以计算⼀个浮点数的绝对值。import math
print(math.fabs(-1.1))
print(math.fabs(-0.0))
print(math.fabs(0.0))
print(math.fabs(1.1))
在实际中,float的绝对值表⽰为⼀个正值。
要确定⼀个值的符号,以便为⼀组值指定相同的符号或者⽐较两个值,可以使⽤copysign()来设置正确值的符号。
import math
HEADINGS = ('f', 's', '< 0', '> 0', '= 0')
print('{:^5} {:^5} {:^5} {:^5} {:^5}'.format(*HEADINGS))
print('{:-^5} {:-^5} {:-^5} {:-^5} {:-^5}'.format(
'', '', '', '', '',
))
VALUES = [
-1.0,
0.0,
1.0,
float('-inf'),
float('inf'),
float('-nan'),
float('nan'),
]
for f in VALUES:
s = pysign(1, f))
print('{:5.1f} {:5d} {!s:5} {!s:5} {!s:5}'.format(
f, s, f < 0, f > 0, f == 0,
))
还需要另⼀个类似copysign()的函数,因为不能将nan和-nan与其他值直接⽐较。
1.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:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论