文章来自《Python cookbook》.

翻译仅仅是为了个人学习,其它商业版权纠纷与此无关!

-- Zoom.Quiet [2004-08-11 01:34:18]

生成一个浮点数定义的range

.16 Spanning a Range Defined by Floats

Credit: Dinu C. Gherman, Paul M. Winkler

问题 Problem

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

你需要一个代数表达式,就象内建函数range一样。但是它要的是浮点数(range仅仅在整数上工作)

解决 Solution

Although this functionality is not available as a built-in, it's not hard to code it with a loop:

尽管这个功能不能象内建那样使用。使用一个循环,不难写出它的代码。

   1 def frange(start, end=None, inc=1.0):
   2     "A range-like function that does accept float increments..."
   3 
   4     if end == None:
   5         end = start + 0.0     # Ensure a float value for 'end'
   6         start = 0.0
   7     assert inc                # sanity check
   8 
   9     L = []
  10     while 1:
  11         next = start + len(L) * inc
  12         if inc > 0 and next >= end:
  13             break
  14         elif inc < 0 and next <= end:
  15             break
  16         L.append(next)
  17 
  18     return L

讨论 Discussion

Sadly missing in the Python standard library, the function in this recipe lets you use ranges, just as with the built-in function range, but with float arguments.

遗憾的是在python标准库里没有这样的函数, 这个配方让你象使用内建函数range一样构造range,不同的是你能使用float参数。

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

尽管许多理论可以用在这儿,但是这个函数在实际中比在理论上更有用。始终同浮点数打交道的人有许多所谓的“战争”故事,比如因为没有考虑到当代硬件比较浮点数时的奇怪事,而造成十亿美元项目的失败。但是就一般情况来说, 这个配方的简单方法总还是奏效的。

You can get a substantial speed boost by preallocating the list instead of calling append repeatedly. This also allows you to get rid of the conditionals in the inner loop. For one element, this version is barely faster, but with more than 10 elements it's consistently about 5 times faster梩he kind of performance ratio that is worth caring about. I get identical output for every test case I can think of:

通过预先分配list来代替重复调用调用append, 使你能够得到一个真正的速度提升。这也允许你除掉在内部循环的条件。对于一个元素来说。这个版本不是更快。但是对于十个元素,它快5倍。这种性能比值得考虑。我为每一个我能想到的测试用例得到相同的输出:

   1 def frange2(start, end=None, inc=1.0):
   2     "A faster range-like function that does accept float increments..."
   3     if end == None:
   4         end = start + 0.0
   5         start = 0.0
   6     else: start += 0.0 # force it to be a float
   7 
   8     count = int((end - start) / inc)
   9     if start + count * inc != end:
  10         # Need to adjust the count. AFAICT, it always comes up one short.
  11         count += 1
  12 
  13     L = [start] * count
  14     for i in xrange(1, count):
  15         L[i] = start + i * inc
  16 
  17     return L

Both versions rely on a single multiplication and one addition to compute each item, to avoid accumulating error by repeated additions. This is why, for example, the body of the for loop in frange2 is not:

但是版本依赖于一个单独的乘法和一个加法去计算每一个元素。是为了避免通过重复增加的计算错误。这就是为什么, 例如, for循环体在frange2不是:

L[i] = L[i-1] + inc 

In Python 2.2, if all you need to do is loop on the result of frange, you can save some memory by turning this function into a simple generator, yielding an iterator when you call it:

在python2.2, 如果你需要做的是在一个frange的结果上循环。你可以通过把这个函数转换成一个简单的产生器来节约内存,当你调用它时候,让步于一个迭代子;

   1 from _ _future_ _ import generators
   2 
   3 def frangei(start, end=None, inc=1.0):
   4     "An xrange-like simple generator that does accept float increments..."
   5 
   6     if end == None:
   7         end = start + 0.0
   8         start = 0.0
   9     assert inc                # sanity check
  10 
  11     i = 0
  12     while 1:
  13         next = start + i * inc
  14         if inc > 0 and next >= end:
  15             break
  16         elif inc < 0 and next <= end:
  17             break
  18         yield next
  19         i += 1

If you use this recipe a lot, you should probably take a look at Numeric Python and other third-party packages that take computing with floating-point numbers seriously. This recipe, for example, will not scale well to very large ranges, while those defined in Numeric Python will.

如果你大量的使用这个配方 ,你应该去看看Numeric python和其他第三方真正使用浮点数计算的包。 例如, 这个配方不适合产生非常大的range, 虽然那些将定义在Numeric pyhon

参考 See Also

Documentation for the range built-in function in the Library Reference; Numeric Python (http://www.pfdubois.com/numpy/).