开发者

Calculating a range of an exact number of values in Python

开发者 https://www.devze.com 2022-12-24 09:45 出处:网络
I\'m building a range between two numbers (floats) and I\'d like this range to be of an exact fixed length (no more, no les开发者_如何学Cs).range and arange work with steps, instead. To put things int

I'm building a range between two numbers (floats) and I'd like this range to be of an exact fixed length (no more, no les开发者_如何学Cs). range and arange work with steps, instead. To put things into pseudo Python, this is what I'd like to achieve:

start_value = -7.5
end_value = 0.1
my_range = my_range_function(star_value, end_value, length=6)

print my_range
[-7.50,-5.98,-4.46,-2.94,-1.42,0.10]

This is essentially equivalent to the R function seq which can specify a sequence of a given length. Is this possible in Python?

Thanks.


Use linspace() from NumPy.

>>> from numpy import linspace
>>> linspace(-7.5, 0.1, 6)
array([-7.5 , -5.98, -4.46, -2.94, -1.42,  0.1])
>>> linspace(-7.5, 0.1, 6).tolist()
[-7.5, -5.9800000000000004, -4.46, -2.9399999999999995, -1.4199999999999999, 0.10000000000000001]

It should be the most efficient and accurate.


See Recipe 66472: frange(), a range function with float increments (Python) with various float implementations, their pros and cons.

Alternatively, if precision is important to you, work with decimal.Decimal instead of float (convert to and then back) as answered in Python decimal range() step value.


def my_function(start, end, length):
    len = length - 1
    incr = (end-start) / len
    r = [ start ]
    for i in range(len):
        r.append ( r[i] + incr )
    return r


How about this:

def my_range_function(start, end, length):
    if length <= 1: return [ start ]
    step = (end - start) / (length - 1)
    return [(start + i * step) for i in xrange(length)]

For your sample range, it returns:

[-7.5, -5.9800000000000004, -4.46,
 -2.9399999999999995, -1.4199999999999999, 0.099999999999999645]

Of course it's full of round errors, but that's what you get when working with floats.


In order to handle the rounding errors, the following code utilizes Python's decimal module. You can set the rounding; for this sample I've set it to two decimal points via round_setting = '.01'. In order to handle any rounding errors, the last step is adjusted to the remainder.

Code

#!/usr/bin/env python
# encoding: utf-8
from __future__ import print_function
import math
import decimal


start_value = -7.5
end_value = 0.1
num_of_steps = 6

def my_range(start_value, end_value, num_of_steps):
    round_setting = '.01'
    start_decimal = decimal.Decimal(str(start_value)).quantize(
        decimal.Decimal(round_setting))
    end_decimal = decimal.Decimal(str(end_value)).quantize(
        decimal.Decimal(round_setting))
    num_of_steps_decimal = decimal.Decimal(str(num_of_steps)).quantize(
        decimal.Decimal(round_setting))
    step_decimal = ((end_decimal - start_decimal) / 
        num_of_steps_decimal).quantize(decimal.Decimal(round_setting))
    # Change the last step in case there are rounding errors
    last_step_decimal = (end_decimal - ((num_of_steps - 1) * step_decimal) -
            start_decimal).quantize(decimal.Decimal(round_setting))
    print('Start value = ', start_decimal)
    print('End value = ', end_decimal)
    print('Number of steps = ', num_of_steps)
    print('Normal step for range = ', step_decimal)
    print('Last step used for range = ', last_step_decimal)

my_range(start_value, end_value, num_of_steps)

Output

$ ./fixed_range.py 
Start value =  -7.50
End value =  0.10
Number of steps =  6
Normal step for range =  1.27
Last step used for range =  1.25

From there you can use the normal step and the last step to create your list.

0

精彩评论

暂无评论...
验证码 换一张
取 消