from math import log10, ceil
from itertools import tee, count, takewhile, dropwhile, izip, chain, imap

# von Yalu:  http://www.mikrocontroller.net/topic/261919#2718301

def e_series(ser, low, high, adj=False):
    '''
    generate a range of E<ser> values
    low:  lower bound
    high: upper bound (must be >= low)
    ser:  one of 3, 6, 12, 24, 48, 96, 192, ...
    adj:  if True, adjacent values below low and above high are generated too
    '''

    # avoid unlovely effects due to rounding errors
    low  *= 1 - 1e-15
    high *= 1 + 1e-15

    if ser < 48:
        # for E3 to E24: crappy "quasi"-exponential series rounded to 1 digit
        series = [round(10**(i/24.)-abs(i-11)/90.+.1, 1) for i in range(0, 24, 24/ser)]
    else:
        # for E48 and higher: clean exponential series rounded to 2 digits
        series = [round(10**(i/192.)+i**3*4e-11, 2) for i in range(0, 192, 192/ser)]
    # some magic stuff from itertools follows:

    # generate two infinite sequences of ascending values, displaced by one element
    g0,g1 = tee(val*10**i for i in count(int(ceil(log10(low)))-1) for val in series)
    g1.next()

    # zip both sequences together and take all elements between the given bounds
    g = takewhile(lambda (x0,x1): x0<=high, dropwhile(lambda (x0,x1): x1<low, izip(g0, g1)))
    first = g.next()

    # if adj=False, return all values in [low,high] else add two extra values
    return chain(first, imap(lambda (x0,x1): x1, g)) if adj else imap(lambda (x0,x1): x0, g)


if __name__ == '__main__':
    for r in e_series(3, .004, 3000, True):
        print r,
    print
