Search code examples
pythonnumpylinspace

how to efficiently create a range of float numbers


Suppose I want to create a set of float numbers starting from 0.1 to 0.00001 as first diving by two and then diving by 5. In other words, I'd like to get the numbers shown below.

0.1
0.05
0.01
0.005
0.001
0.0005
0.0001
0.00005
0.00001

For this small example, I wrote the following code snippet which works fine.

import numpy as np
def format_float(num):
    return np.format_float_positional(num, trim='-')

num = 0.1

for j in range(9):
    if j ==0:
        rate=np.round(num*(0.1),j+1)
        print(format_float(num))
    elif ( (j+1) % 2) != 0:
        num=np.round(num*(0.2),j+1)
        print(format_float(num))
    else:
        num =np.round(num/2,j+1)
        print(format_float(num))

My question is if there is a more elegant way to perform this operation given different rules. For instance, suppose I would like to get the number between x and y where the rule is to first divide by k and then divide by l in order. I believe this should be managable through linspace, but I could not do it.


Solution

  • In [1]: import numpy as np
    
    In [2]: np.repeat(1 / 10**np.arange(1, 5), 2)[1:] * np.array([1., 5.]*4)[:-1]
    Out[2]: array([0.1   , 0.05  , 0.01  , 0.005 , 0.001 , 0.0005, 0.0001])
    

    Generalizing for any "pattern":

    def rates(smallest_magnitude, pattern):
        n = len(pattern)
        pows = np.repeat(1 / 10**np.arange(1, smallest_magnitude), n)[(n-1):]
        mults = np.array(pattern * (smallest_magnitude - 1))[:-(n-1)]
        return np.round(pows * mults, smallest_magnitude)
    

    Demo:

    In [4]: print(*rates(5, [1, 5]))  # Your original 'pattern'
    0.1 0.05 0.01 0.005 0.001 0.0005 0.0001
    
    In [5]: print(*rates(5, [2, 4, 8]))
    0.2 0.04 0.08 0.02 0.004 0.008 0.002 0.0004 0.0008 0.0002
    
    In [6]: print(*rates(5, [3, 5, 7, 9]))
    0.3 0.05 0.07 0.09 0.03 0.005 0.007 0.009 0.003 0.0005 0.0007 0.0009 0.0003