changed share fraction displays to include confidence intervals and put them all...
[p2pool.git] / p2pool / util / math.py
1 from __future__ import absolute_import, division
2
3 import math
4 import random
5
6 def median(x, use_float=True):
7     # there exist better algorithms...
8     y = sorted(x)
9     if not y:
10         raise ValueError('empty sequence!')
11     left = (len(y) - 1)//2
12     right = len(y)//2
13     sum = y[left] + y[right]
14     if use_float:
15         return sum/2
16     else:
17         return sum//2
18
19 def shuffled(x):
20     x = list(x)
21     random.shuffle(x)
22     return x
23
24 def shift_left(n, m):
25     # python: :(
26     if m >= 0:
27         return n << m
28     return n >> -m
29
30 def clip(x, (low, high)):
31     if x < low:
32         return low
33     elif x > high:
34         return high
35     else:
36         return x
37
38 def nth(i, n=0):
39     i = iter(i)
40     for _ in xrange(n):
41         i.next()
42     return i.next()
43
44 def geometric(p):
45     if p <= 0 or p > 1:
46         raise ValueError('p must be in the interval (0.0, 1.0]')
47     if p == 1:
48         return 1
49     return int(math.log1p(-random.random()) / math.log1p(-p)) + 1
50
51 def add_dicts(dicts):
52     res = {}
53     for d in dicts:
54         for k, v in d.iteritems():
55             res[k] = res.get(k, 0) + v
56     return dict((k, v) for k, v in res.iteritems() if v)
57
58 def format(x):
59     prefixes = 'kMGTPEZY'
60     count = 0
61     while x >= 100000 and count < len(prefixes) - 2:
62         x = x//1000
63         count += 1
64     s = '' if count == 0 else prefixes[count - 1]
65     return '%i' % (x,) + s
66
67 def perfect_round(x):
68     a, b = divmod(x, 1)
69     a2 = int(a)
70     if random.random() >= b:
71         return a2
72     else:
73         return a2 + 1
74
75 def ierf(z, steps=10):
76     guess = 0
77     for i in xrange(steps):
78         d = 2*math.e**(-guess**2)/math.sqrt(math.pi)
79         guess = guess - (math.erf(guess) - z)/d
80     return guess
81
82 def binomial_conf_interval(x, n, conf=0.95):
83     # approximate - Wilson score interval
84     z = math.sqrt(2)*ierf(conf)
85     p = x/n
86     topa = p + z**2/2/n
87     topb = z * math.sqrt(p*(1-p)/n + z**2/4/n**2)
88     bottom = 1 + z**2/n
89     return (topa - topb)/bottom, (topa + topb)/bottom
90
91 def interval_to_center_radius((low, high)):
92     return (high+low)/2, (high-low)/2
93
94 if __name__ == '__main__':
95     import random
96     a = 1
97     while True:
98         print a, format(a) + 'H/s'
99         a = a * random.randrange(2, 5)