Comparing NumPy arange and custom range function for producing ranges with decimal increments

后端 未结 3 1481
春和景丽
春和景丽 2021-01-12 02:52

Here\'s a custom function that allows stepping through decimal increments:

def my_range(start, stop, step):
    i = start
    while i < stop:
        yiel         


        
3条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-01-12 03:30

    The difference in endpoints is because NumPy calculates the length up front instead of ad hoc, because it needs to preallocate the array. You can see this in the _calc_length helper. Instead of stopping when it hits the end argument, it stops when it hits the predetermined length.

    Calculating the length up front doesn't save you from the problems of a non-integer step, and you'll frequently get the "wrong" endpoint anyway, for example, with numpy.arange(0.0, 2.1, 0.3):

    In [46]: numpy.arange(0.0, 2.1, 0.3)
    Out[46]: array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8,  2.1])
    

    It's much safer to use numpy.linspace, where instead of the step size, you say how many elements you want and whether you want to include the right endpoint.


    It might look like NumPy has suffered no rounding error when calculating the elements, but that's just due to different display logic. NumPy is truncating the displayed precision more aggressively than float.__repr__ does. If you use tolist to get an ordinary list of ordinary Python scalars (and thus the ordinary float display logic), you can see that NumPy has also suffered rounding error:

    In [47]: numpy.arange(0, 1, 0.1).tolist()
    Out[47]: 
    [0.0,
     0.1,
     0.2,
     0.30000000000000004,
     0.4,
     0.5,
     0.6000000000000001,
     0.7000000000000001,
     0.8,
     0.9]
    

    It's suffered slightly different rounding error - for example, in .6 and .7 instead of .8 and .9 - because it also uses a different means of computing the elements, implemented in the fill function for the relevant dtype.

    The fill function implementation has the advantage that it uses start + i*step instead of repeatedly adding the step, which avoids accumulating error on each addition. However, it has the disadvantage that (for no compelling reason I can see) it recomputes the step from the first two elements instead of taking the step as an argument, so it can lose a great deal of precision in the step up front.

提交回复
热议问题