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()来计算。

运行结果:

grafana math表达式_浮点数


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参数,只要这个参数可以转换为一个整数而不丢值。

运行结果:

grafana math表达式_浮点_02


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会导致开始值为负,所以这是不允许的。

运行结果:

grafana math表达式_操作符_03


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()的结果单独计算对数更精确。

运行结果:

grafana math表达式_操作符_04


求模操作符(%)会计算一个除法表达式的余数(例如,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()计算模所使用的算法与%使用的算法也有所不同,所以结果的符号不同。

运行结果:

grafana math表达式_操作符_05


可使用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