4

I am iterating over an interval of decimal points, using the code in this solution: https://stackoverflow.com/a/13286671/2169327

def seq(start, end, step):
    assert(step != 0)
    sample_count = abs(end - start) / step
    return itertools.islice(itertools.count(start, step), sample_count)

But I have a problem. My step size is going to be approximately 0.001, while my interval is 70.390829 to 70.855549. How to I assure that I actually iterate over as much as the interval as possible? Should I maybe round down to three decimals, to assure that I got as much of the area as possible? With this I mean that I need to start as close to the start, and end as close to the end as possible. Would that help? Any other clever ideas?

Community
  • 1
  • 1
bjornasm
  • 2,211
  • 7
  • 37
  • 62

2 Answers2

3

You can use numpy.linspace, it returns evenly spaced values within a given interval, you just give it three arguments, start, stop, and number of steps:

numpy.linspace(70.390829, 70.855549, 464)

Using 464 samples in this range will be close to a step size of 0.001, but you will be guaranteed by linspace that the first and last values will be exactly equal to your start and stop, so whole range is covered.

qwwqwwq
  • 6,999
  • 2
  • 26
  • 49
  • Thank you! To find the number of samples, I guess you found the difference between the two values, and divided it with the step size I wanted, then flooring the value or something like that? – bjornasm Jul 22 '15 at 21:03
  • yes that is exactly what i did to get number of steps, will update answer – qwwqwwq Jul 22 '15 at 21:06
  • 1
    @bjornasm it's a little more complicated than that. Floor the distance, multiply by the step size, and add that to the starting value. You might need to add a small fudge factor to make sure that rounding doesn't cause `floor` to lose the last value. – Mark Ransom Jul 22 '15 at 21:06
3

Since you seem to be concerned about rounding errors occurring with floats, the following code uses the decimal module to allow you to select whatever precision your application requires:

>>> from decimal import Decimal as D
>>> compare = lambda a, b: (a > b) - (a < b)
>>> def drange(start, stop, step):
        relation = compare(stop, start)
        if not relation:
            raise ValueError('start and stop may not have the same value')
        if compare(relation, 0) != compare(step, 0):
            raise ValueError('step will not allow the sequence to finish')
        while True:
            yield start
            start += step
            if compare(stop, start) != relation:
                break

>>> sequence = tuple(drange(D('70.390829'), D('70.855549'), D('0.001')))
>>> len(sequence)
465

If you are not too worried about floating point rounding errors, you can also use the numbers directly with the drange generator and get a sequence with exactly the same length as with decimals:

>>> sequence = tuple(drange(70.390829, 70.855549, 0.001))
>>> len(sequence)
465
Noctis Skytower
  • 21,433
  • 16
  • 79
  • 117