e_series.py


1
from math import log10, ceil
2
from itertools import tee, count, takewhile, dropwhile, izip, chain, imap
3
4
# von Yalu:  http://www.mikrocontroller.net/topic/261919#2718301
5
6
def e_series(ser, low, high, adj=False):
7
    '''
8
    generate a range of E<ser> values
9
    low:  lower bound
10
    high: upper bound (must be >= low)
11
    ser:  one of 3, 6, 12, 24, 48, 96, 192, ...
12
    adj:  if True, adjacent values below low and above high are generated too
13
    '''
14
15
    # avoid unlovely effects due to rounding errors
16
    low  *= 1 - 1e-15
17
    high *= 1 + 1e-15
18
19
    if ser < 48:
20
        # for E3 to E24: crappy "quasi"-exponential series rounded to 1 digit
21
        series = [round(10**(i/24.)-abs(i-11)/90.+.1, 1) for i in range(0, 24, 24/ser)]
22
    else:
23
        # for E48 and higher: clean exponential series rounded to 2 digits
24
        series = [round(10**(i/192.)+i**3*4e-11, 2) for i in range(0, 192, 192/ser)]
25
    # some magic stuff from itertools follows:
26
27
    # generate two infinite sequences of ascending values, displaced by one element
28
    g0,g1 = tee(val*10**i for i in count(int(ceil(log10(low)))-1) for val in series)
29
    g1.next()
30
31
    # zip both sequences together and take all elements between the given bounds
32
    g = takewhile(lambda (x0,x1): x0<=high, dropwhile(lambda (x0,x1): x1<low, izip(g0, g1)))
33
    first = g.next()
34
35
    # if adj=False, return all values in [low,high] else add two extra values
36
    return chain(first, imap(lambda (x0,x1): x1, g)) if adj else imap(lambda (x0,x1): x0, g)
37
38
39
if __name__ == '__main__':
40
    for r in e_series(3, .004, 3000, True):
41
        print r,
42
    print