1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
| #!/usr/bin/env python
# -*- coding: utf-8 -*-
import math
sqrt = math.sqrt
def gen_imet(func):
def retfunc(self, other):
ret = func(self, other)
self.ave = ret.ave
self.u = ret.u
self.digs = ret.digs
return self
return retfunc
def get_digs(a, b):
if a == 0: return b
elif b == 0: return a
else: return min(a, b)
class PhyStat:
"""
物理实验数据
PhyStat(ave, u = 0.0, digs = 0)
ave 表示平均值,如果传入一列数则自动计算平均值及其标准误差
u 表示标准误差,如果 ave 传入数据列表则此处表示仪器精度
digs 表示有效数字个数,0 表示不限制
"""
def __init__(self, ave, u = 0.0, digs = 0):
"""
对于 ave 为数据列表的情况,使用下面公式计算平均值:
ave = Σx[i] / n
根据下面公式计算标准误差:
S = Sqrt(Σ(x[i]-ave)^2 / (n - 1))
u = Δinst / Sqrt(3)
U = Sqrt(S^2 + u^2)
"""
self.digs = digs
if isinstance(ave, tuple) or isinstance(ave, list):
data = ave
n = len(data)
ave = math.fsum(ave) / n
self.ave = ave
s = 0.0
for i in data:
s += (i - ave) ** 2
s = sqrt(s / (n - 1))
u /= sqrt(3)
self.u = sqrt(s ** 2 + u ** 2)
else:
self.ave = float(ave)
self.u = abs(float(u))
def __repr__(self):
ave = self.ave
exp = int(math.floor(math.log10(ave)))
exp10 = 10 ** exp
ave = ave / exp10
u = self.u / exp10
digs = self.digs
if digs == 0:
ret = '%f ±%f'
else:
ret = '%%.%df ±%%.%df' % (digs, digs)
if exp:
ret = '(%s) E %d' % (ret, exp)
return ret % (ave, u)
__neg__ = lambda self: PhyStat(-self.ave, self.u, self.digs)
__pos__ = lambda self: self
__abs__ = lambda self: PhyStat(abs(self.ave), self.u, self.digs)
def __add__(self, other):
if isinstance(other, PhyStat):
ave = self.ave + other.ave
u = sqrt(self.u ** 2 + other.u ** 2)
digs = get_digs(self.digs, other.digs)
return PhyStat(ave, u, digs)
else:
ave = self.ave + other
return PhyStat(ave, self.u, self.digs)
__radd__ = __add__
__sub__ = lambda self, other: self + (-other)
__rsub__ = lambda self, other: other + (-self)
def __mul__(self, other):
if isinstance(other, PhyStat):
a = self.ave
b = other.ave
ave = a * b
u = ave * sqrt((self.u / a) ** 2 + (other.u / b) ** 2)
digs = get_digs(self.digs, other.digs)
return PhyStat(ave, u, digs)
else:
ave = self.ave * other
u = self.u * other
return PhyStat(ave, u, self.digs)
__rmul__ = __mul__
def __div__(self, other):
if isinstance(other, PhyStat):
return self * other ** -1
else:
return (1.0 / other) * self
__rdiv__ = lambda self, other: other * self ** -1
def __pow__(self, other):
a = self.ave
ave = a ** other
u = abs(other * self.u / a * ave)
return PhyStat(ave, u, self.digs)
__iadd__ = gen_imet(lambda self, other: self + other)
__isub__ = gen_imet(lambda self, other: self - other)
__imul__ = gen_imet(lambda self, other: self * other)
__idiv__ = gen_imet(lambda self, other: self / other)
__ipow__ = gen_imet(lambda self, other: self ** other)
__int__ = lambda self: int(self.ave)
__long__ = lambda self: long(self.ave)
__float__ = lambda self: self.ave |
Comments