Recipe19.1.Writing a range-like Function with Float Increments


Recipe 19.1. Writing a range-like Function with Float Increments

Credit: Dinu Gherman, Paul Winkler, Stephen Levings

Problem

You need an arithmetic progression, like the built-in xrange but with float values (xrange works only on integers).

Solution

Although float arithmetic progressions are not available as built-ins, it's easy to code a generator to supply them:

import itertools def frange(start, end=None, inc=1.0):     "An xrange-like generator which yields float values"     # imitate range/xrange strange assignment of argument meanings     if end is None:         end = start + 0.0     # Ensure a float value for 'end'         start = 0.0     assert inc                # sanity check     for i in itertools.count( ):         next = start + i * inc         if (inc>0.0 and next>=end) or (inc<0.0 and next<=end):             break         yield next

Discussion

Sadly missing in the Python Standard Library, the generator in this recipe lets you use arithmetic progressions, similarly to the built-in xrange but with float values.

Many theoretical restrictions apply, but this generator is more useful in practice than in theory. People who work with floating-point numbers all the time tell many war stories about billion-dollar projects that failed because someone did not take into consideration the strange things that modern hardware can do, at times, when comparing floating-point numbers. But for pedestrian cases, simple approaches like this recipe generally work.

This observation by no means implies that you can afford to ignore the fundamentals of numerical analysis, if your programs need to do anything at all with floating-point numbers! For example, in this recipe, we rely on a single multiplication and one addition to compute each item, to avoid accumulating error by repeated additions. Precision would suffer in a potentially dangerous way if we "simplified" the first statement in the loop body to something like:

    next += inc

as might appear very tempting, were it not for those numerical analysis considerations.

One variation you may want to consider is based on pre-computing the number of items that make up the bounded arithmetic progression:

import math def frange1(start, end=None, inc=1.0):     if end == None:         end = start + 0.0     # Ensure a float value for 'end'         start = 0.0     nitems = int(math.ceil((end-start)/inc))     for i in xrange(nitems):         yield start + i * inc

This frange1 version may or may not be faster than the frange version shown in the solution; if the speed of this particular generator is crucial to your programs, it's best to try both versions and measure resulting times. In my limited benchmarking, on most of the hardware I have at hand, frange1 does appear to be consistently faster.

Talking about speedbelieve it or not, looping with for i in itertools.count( ) is measurably faster than apparently obvious lower-level alternatives such as:

    i = 0     while True:         ...loop body unchanged...         yield next         i += 1

Do consider using itertools any time you want speed, and you may be in for more of these pleasant surprises.

If you work with floating-point numbers, you should definitely take a look at Numeric and other third-party extension packages that make Python such a powerful language for floating-point computations. For example, with Numeric, you could code something like:

import math, Numeric def frange2(start, end=None, inc=1.0, typecode=None):     if end == None:         end = start + 0.0     # Ensure a float value for 'end'         start = 0.0     nitems = math.ceil((end-start)/inc)     return Numeric.arange(nitems) * inc + start

This one is definitely going to be faster than both frange and frange1 if you need to collect all of the progression's items into a sequence.

See Also

Documentation for the xrange built-in function, and the itertools and math modules, in the Library Reference; Numeric Python (http://www.pfdubois.com/numpy/).



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net