¿Cómo usar un valor de paso de rango decimal ()?

¿Hay alguna manera de pasar de 0 a 1 por 0.1?

Pensé que podría hacerlo de la siguiente manera, pero falló:

for i in range(0, 1, 0.1):
    print i

En cambio, dice que el argumento del paso no puede ser cero, lo que no esperaba.

preguntado el 25 de enero de 09 a las 08:01

int (0.1) == 0, por lo que el paso en realidad es cero. Puede ser inesperado, pero es cero. Es posible que desee volver a formular su pregunta para reflejar el hecho de que no esperaba esto. Decir "no lo es" es falso y engañoso. -

Por cierto, se puede enrollar un trazador de líneas corto usando itertools.takewhile y itertools.count. No es mejor que drange Sin embargo, en cuanto al rendimiento. -

Es vergonzoso que el rango de Python no permita esto, dado lo fácil que es implementar un generador que lo haga incluso sin acumular errores de redondeo. Diablos, incluso el seq herramienta en GNU coreutils permite hacer seq 0 0.1 1 sin errores de redondeo! -

@josch: seq usa la C long double escriba internamente, y is sujeto a errores de redondeo. Por ejemplo en mi máquina, seq 0 0.1 1 da 1 como su última salida (como se esperaba), pero seq 1 0.1 2 da 1.9 como la última salida (en lugar de la esperada 2). -

Para mayor comodidad, la sugerencia de @ Kos se puede implementar como itertools.takewhile(lambda x: (x+0.05)<1, itertools.count(0,0.1)) or itertools.islice(itertools.count(0,0.1), 10) (después de que tengas import itertools), aunque no he probado cuál es más eficiente -

30 Respuestas

En lugar de usar un paso decimal directamente, es mucho más seguro expresar esto en términos de cuántos puntos desea. De lo contrario, es probable que el error de redondeo de punto flotante le dé un resultado incorrecto.

Puede utilizar el espacio lineal funcionar desde el NumPy biblioteca (que no forma parte de la biblioteca estándar pero es relativamente fácil de obtener). linspace toma una serie de puntos para devolver y también le permite especificar si se debe incluir o no el punto final correcto:

>>> np.linspace(0,1,11)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1. ])
>>> np.linspace(0,1,10,endpoint=False)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

Si realmente desea utilizar un valor de paso de punto flotante, puede, con numpy.arange.

>>> import numpy as np
>>> np.arange(0.0, 1.0, 0.1)
array([ 0. ,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9])

Error de redondeo de coma flotante causar problemas, sin embargo. Aquí hay un caso simple donde el error de redondeo causa arange para producir una matriz de longitud 4 cuando solo debería producir 3 números:

>>> numpy.arange(1, 1.3, 0.1)
array([1. , 1.1, 1.2, 1.3])

Respondido 10 Feb 20, 09:02

numpy es un componente tan omnipresente de python que considero que esta respuesta es la más 'pitónica' de todas. - ataque aéreo

@AndreTerra El problema es que @ numpy @ es un paquete de terceros y agrega mucha sobrecarga en términos de administración de dependencias, almacenamiento (para el paquete en sí), etc. Dependiendo de lo que esté haciendo el desarrollador, puede ser imposible de usar eso. - baleksandar

Disculpe, pero no entendí el error de redondeo de punto flotante en la última parte desde np.linspace(1.,1.3,4) y np.arange(1.,1.3,0.1) dar exactamente la misma salida - código muerto

@deadcode La razón es que np. naranja se define para producir un rango [start,stop) (es decir, excluyendo stop), por lo que no se esperaría que 1.3 se incluyera en la lista. Ver esta pregunta por qué todavía está incluido y qué hacer contra él. - dennis

La cantidad de paquete que se usa posiblemente no es un indicador de si es "Pythonic". - Alex Salón

El rango de Python () solo puede hacer números enteros, no coma flotante. En su caso específico, puede utilizar una lista de comprensión en su lugar:

[x * 0.1 for x in range(0, 10)]

(Reemplace la llamada al rango con esa expresión).

Para el caso más general, es posible que desee escribir una función o un generador personalizados.

Respondido el 25 de enero de 09 a las 10:01

Aún mejor, podría usar un generador de comprensión si está trabajando con Python 2.4+. (x * 0.1 for x in range(0, 10)). - JAB

Incluso mejor poner x/10 en lugar de x * 0.1 : D Nada especial en realidad, pero algunos números serán más precisos, por ejemplo, para 3*0.1 se obtiene 0.30000000000000004, mientras que por 3/10 obtienes 0.3 :) - Tipo de

3/10 me da 0, no 0.3. 3 / 10.0 da 0.29999999999999999. Python 2.6. - usuario25148

@LarsWirzenius: en Python 2.2+, from __future__ import division; 3/10 devuelve 0.3. Este comportamiento es el predeterminado en Python 3.x. - Benjamin Hodgson ♦

La función round también se puede usar lst = [round (x * 0.10,2) for x in range (0,10)] - MARCA

sobre la base de 'xrange ([inicio], detener [, paso])', puede definir un generador que acepte y produzca cualquier tipo que elija (apéguese a los tipos que admiten + y <):

>>> def drange(start, stop, step):
...     r = start
...     while r < stop:
...         yield r
...         r += step
...         
>>> i0=drange(0.0, 1.0, 0.1)
>>> ["%g" % x for x in i0]
['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1']
>>> 

Respondido el 25 de enero de 09 a las 11:01

Esto tiene problemas de redondeo. Por favor mire aquí: code.activestate.com/recipes/66472 - Christian Oudard

Lo extendería un poco para la otra dirección con a (mientras r> detener) y un paso r - = correspondiente para dar la dirección opuesta. - user318904

Hice una función xfrange sin los problemas de precisión de flotación mencionados anteriormente. Échale un vistazo ;) stackoverflow.com/questions/477486/… - Carlos vega

Estás acumulando errores de redondeo. Utilice esto en su lugar: `i = 0; r = iniciar mientras r <detener: i + = 1; r = inicio + i * paso; rendimiento r` - cees timmerman

Esto es de pythoncentral.io/pythons-range-function-explained (y otras fuentes de documentación de Python) - Apóstoles

Incrementar la magnitud de i para el bucle y luego redúzcalo cuando lo necesite.

for i * 100 in range(0, 100, 10):
    print i / 100.0

EDITAR: Honestamente, no puedo recordar por qué pensé que funcionaría sintácticamente

for i in range(0, 11, 1):
    print i / 10.0

Eso debería tener el resultado deseado.

Respondido 01 Feb 15, 20:02

Creo que encontrará que range () funciona con números enteros, en cuyo caso esta sería la única solución, usando la misma función al menos. - Mateo Scharley

@cmsjr creative: D Solo una pequeña cosa: divida por 100.0 para evitar que Python trunque el resultado si está usando Python 2.x. Creo que en 3.0, funcionará como lo codificó. - Dana

for i * 100 in range(0, 100, 10): SyntaxError: no se puede asignar al operador - Anne van Rossum

NumPy es un poco exagerado, creo.

[p/10 for p in range(0, 10)]
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

En general, para hacer un paso a1/x hasta y tu harías

x=100
y=2
[p/x for p in range(0, int(x*y))]
[0.0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99]

(1/x produjo menos ruido de redondeo cuando probé).

Respondido 28 Feb 17, 02:02

scipy tiene una función incorporada arange que generaliza Python range() constructor para satisfacer sus necesidades de manipulación de flotadores.

from scipy import arange

contestado el 17 de mayo de 14 a las 21:05

Esto es exactamente lo mismo arange puedes encontrar en numpy: >>> import scipy >>> import numpy >>> numpy.arange is scipy.arange regresará True. - iFreilicht

Similar a R's seq función, éste devuelve una secuencia en cualquier orden dado el valor de paso correcto. El último valor es igual al valor de parada.

def seq(start, stop, step=1):
    n = int(round((stop - start)/float(step)))
    if n > 1:
        return([start + step*i for i in range(n+1)])
    elif n == 1:
        return([start])
    else:
        return([])

Resultados

seq(1, 5, 0.5)

[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]

seq(10, 0, -1)

[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

seq(10, 0, -2)

[10, 8, 6, 4, 2, 0]XNUMX

seq(1, 1)

[1]

Respondido 03 Feb 18, 09:02

Esta es una gran respuesta para alguien que quiere obtener una sin meterse demasiado en Python. - Chani

Eso fue casi lo que estaba buscando - ten en cuenta que seq(0.5, 3.0) devoluciones [0.5, 1.5, 2.5, 3.5]. Para evitar que las últimas entradas estén fuera de rango, reemplace n = int(round(... con n = int(floor(... con la linea from math import floor en la parte superior (arriba def seq(...). - AmigoFX

@FriendFX ¡No hagas esto! Si floor es usado seq(0.2, 0.9, 0.1) no podrá alcanzar el punto final correcto y volverá [0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7, 0.8] - fdermishin

@ user502144: Buena captura, gracias. Supongo que tengo que conformarme con una de las soluciones más complejas para mantenerlo en general. - AmigoFX

La función incorporada range () devuelve una secuencia de valores enteros, me temo, por lo que no puede usarla para hacer un paso decimal.

Yo diría que solo usa un bucle while:

i = 0.0
while i <= 1.0:
    print i
    i += 0.1

Si tiene curiosidad, Python está convirtiendo su 0.1 a 0, por lo que le dice que el argumento no puede ser cero.

Respondido el 25 de enero de 09 a las 10:01

¡No hagas esto! Añadiendo .1 10 veces no es lo mismo que sumar 1! docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html - gato

[x * 0.1 for x in range(0, 10)] 

en Python 2.7x le da el resultado de:

[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]

pero si usas:

[ round(x * 0.1, 1) for x in range(0, 10)]

te da lo deseado:

[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

contestado el 14 de mayo de 12 a las 03:05

Aquí hay una solución usando itertools:

import itertools

def seq(start, end, step):
    if step == 0:
        raise ValueError("step must not be 0")
    sample_count = int(abs(end - start) / step)
    return itertools.islice(itertools.count(start, step), sample_count)

Ejemplo de uso:

for i in seq(0, 1, 0.1):
    print(i)

respondido 23 nov., 18:13

En aras de la integridad, debe calcular el valor absoluto de la variable sample_count, de esa manera su función también funcionará para un inicio negativo (es decir, de -10 a 10) - eliminarman

import numpy as np
for i in np.arange(0, 1, 0.1): 
    print i 

Respondido el 07 de Septiembre de 12 a las 03:09

esto tiene el problema del redondeo, cite: "Cuando se usa un paso que no es entero, como 0.1, los resultados a menudo no serán consistentes". - docs.scipy.org/doc/numpy/reference/generated/numpy.arange.html - galactica

Y si hace esto con frecuencia, es posible que desee guardar la lista generada r

r=map(lambda x: x/10.0,range(0,10))
for i in r:
    print i

Respondido el 25 de enero de 09 a las 10:01

Mis versiones usan la función de rango original para crear índices multiplicativos para el cambio. Esto permite la misma sintaxis a la función de rango original. Hice dos versiones, una usando float y otra usando Decimal, porque descubrí que en algunos casos quería evitar la deriva de redondeo introducida por la aritmética de punto flotante.

Es coherente con los resultados de conjuntos vacíos como en range / xrange.

Pasar solo un valor numérico a cualquiera de las funciones devolverá la salida del rango estándar al valor máximo entero del parámetro de entrada (por lo que si le dio 5.5, devolvería el rango (6)).

Editar: el siguiente código ahora está disponible como paquete en pypi: Franjas

## frange.py
from math import ceil
# find best range function available to version (2.7.x / 3.x.x)
try:
    _xrange = xrange
except NameError:
    _xrange = range

def frange(start, stop = None, step = 1):
    """frange generates a set of floating point values over the 
    range [start, stop) with step size step

    frange([start,] stop [, step ])"""

    if stop is None:
        for x in _xrange(int(ceil(start))):
            yield x
    else:
        # create a generator expression for the index values
        indices = (i for i in _xrange(0, int((stop-start)/step)))  
        # yield results
        for i in indices:
            yield start + step*i

## drange.py
import decimal
from math import ceil
# find best range function available to version (2.7.x / 3.x.x)
try:
    _xrange = xrange
except NameError:
    _xrange = range

def drange(start, stop = None, step = 1, precision = None):
    """drange generates a set of Decimal values over the
    range [start, stop) with step size step

    drange([start,] stop, [step [,precision]])"""

    if stop is None:
        for x in _xrange(int(ceil(start))):
            yield x
    else:
        # find precision
        if precision is not None:
            decimal.getcontext().prec = precision
        # convert values to decimals
        start = decimal.Decimal(start)
        stop = decimal.Decimal(stop)
        step = decimal.Decimal(step)
        # create a generator expression for the index values
        indices = (
            i for i in _xrange(
                0, 
                ((stop-start)/step).to_integral_value()
            )
        )  
        # yield results
        for i in indices:
            yield float(start + step*i)

## testranges.py
import frange
import drange
list(frange.frange(0, 2, 0.5)) # [0.0, 0.5, 1.0, 1.5]
list(drange.drange(0, 2, 0.5, precision = 6)) # [0.0, 0.5, 1.0, 1.5]
list(frange.frange(3)) # [0, 1, 2]
list(frange.frange(3.5)) # [0, 1, 2, 3]
list(frange.frange(0,10, -1)) # []

Respondido el 18 de diciembre de 12 a las 22:12

¿Cómo se puede controlar frange trabajar si la parada es None? Esa parte del código ya ni siquiera considera el tamaño del paso. - Josch

@josch range tiene dos firmas: range(stop), que asume un valor predeterminado start=0, step=1 y range(start, stop, step), donde no se hacen suposiciones. frange refleja eso. Al usar el range(stop) firma, ambos frange y drange comienzan en 0 e incrementan en 1, por lo que su comportamiento es idéntico al regular range(stop) comportamiento con parada redondeada al entero más cercano. - Nisan.H

more_itertools es una biblioteca de terceros que implementa una numeric_range herramienta:

import more_itertools as mit


for x in mit.numeric_range(0, 1, 0.1):
    print("{:.1f}".format(x))

Salida

0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9

Esta herramienta también funciona para Decimal y Fraction.

Respondido 09 Feb 18, 00:02

Mejor solución: sin error de redondeo

>>> step = .1
>>> N = 10     # number of data points
>>> [ x / pow(step, -1) for x in range(0, N + 1) ]

[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

O, para un rango establecido en lugar de puntos de datos establecidos (por ejemplo, función continua), use:

>>> step = .1
>>> rnge = 1     # NOTE range = 1, i.e. span of data points
>>> N = int(rnge / step
>>> [ x / pow(step,-1) for x in range(0, N + 1) ]

[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

Para implementar una función: reemplace x / pow(step, -1) con f( x / pow(step, -1) )y definir f.
Por ejemplo:

>>> import math
>>> def f(x):
        return math.sin(x)

>>> step = .1
>>> rnge = 1     # NOTE range = 1, i.e. span of data points
>>> N = int(rnge / step)
>>> [ f( x / pow(step,-1) ) for x in range(0, N + 1) ]

[0.0, 0.09983341664682815, 0.19866933079506122, 0.29552020666133955, 0.3894183423086505, 
 0.479425538604203, 0.5646424733950354, 0.644217687237691, 0.7173560908995228,
 0.7833269096274834, 0.8414709848078965]

Respondido 02 Jul 20, 09:07

Esta es mi solución para obtener rangos con pasos flotantes.
Con esta función no es necesario importar numpy ni instalarlo.
Estoy bastante seguro de que podría mejorarse y optimizarse. Siéntete libre de hacerlo y publícalo aquí.

from __future__ import division
from math import log

def xfrange(start, stop, step):

    old_start = start #backup this value

    digits = int(round(log(10000, 10)))+1 #get number of digits
    magnitude = 10**digits
    stop = int(magnitude * stop) #convert from 
    step = int(magnitude * step) #0.1 to 10 (e.g.)

    if start == 0:
        start = 10**(digits-1)
    else:
        start = 10**(digits)*start

    data = []   #create array

    #calc number of iterations
    end_loop = int((stop-start)//step)
    if old_start == 0:
        end_loop += 1

    acc = start

    for i in xrange(0, end_loop):
        data.append(acc/magnitude)
        acc += step

    return data

print xfrange(1, 2.1, 0.1)
print xfrange(0, 1.1, 0.1)
print xfrange(-1, 0.1, 0.1)

El resultado es:

[1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]
[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1]
[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0]

Respondido el 12 de diciembre de 13 a las 17:12

Hay un error al perder el último valor si está dentro de 1 paso del valor de parada. es decir, xfrange (1,10,2) solo hace 1,3,5,7, faltan 9 - lóbulo

Para referencia y otros lectores, compare esta implementación con esta stackoverflow.com/a/477610/54964. Esto no parece tener grandes problemas de flotación. - Léo Léopold Hertz 준영

@carlosvega ¿Puedes confirmar por qué Lobe obtiene su resultado? - Léo Léopold Hertz 준영

Para la integridad de la boutique, una solución funcional:

def frange(a,b,s):
  return [] if s > 0 and a > b or s < 0 and a < b or s==0 else [a]+frange(a+s,b,s)

Respondido el 12 de Septiembre de 15 a las 08:09

Sorprendido, nadie ha mencionado todavía la solución recomendada en los documentos de Python 3:

Ver también:

  • El receta linspace muestra cómo implementar una versión perezosa de rango que sea adecuada para aplicaciones de punto flotante.

Una vez definida, la receta es fácil de usar y no requiere numpy o cualquier otra biblioteca externa, pero funciona como numpy.linspace(). Tenga en cuenta que en lugar de un step argumento, el tercero num argumento especifica el número de valores deseados, por ejemplo:

print(linspace(0, 10, 5))
# linspace(0, 10, 5)
print(list(linspace(0, 10, 5)))
# [0.0, 2.5, 5.0, 7.5, 10]

Cito una versión modificada de la receta completa de Python 3 de Andrew Barnert a continuación:

import collections.abc
import numbers

class linspace(collections.abc.Sequence):
    """linspace(start, stop, num) -> linspace object

    Return a virtual sequence of num numbers from start to stop (inclusive).

    If you need a half-open range, use linspace(start, stop, num+1)[:-1].
    """
    def __init__(self, start, stop, num):
        if not isinstance(num, numbers.Integral) or num <= 1:
            raise ValueError('num must be an integer > 1')
        self.start, self.stop, self.num = start, stop, num
        self.step = (stop-start)/(num-1)
    def __len__(self):
        return self.num
    def __getitem__(self, i):
        if isinstance(i, slice):
            return [self[x] for x in range(*i.indices(len(self)))]
        if i < 0:
            i = self.num + i
        if i >= self.num:
            raise IndexError('linspace object index out of range')
        if i == self.num-1:
            return self.stop
        return self.start + i*self.step
    def __repr__(self):
        return '{}({}, {}, {})'.format(type(self).__name__,
                                       self.start, self.stop, self.num)
    def __eq__(self, other):
        if not isinstance(other, linspace):
            return False
        return ((self.start, self.stop, self.num) ==
                (other.start, other.stop, other.num))
    def __ne__(self, other):
        return not self==other
    def __hash__(self):
        return hash((type(self), self.start, self.stop, self.num))

respondido 03 mar '18, 08:03

Puede utilizar esta función:

def frange(start,end,step):
    return map(lambda x: x*step, range(int(start*1./step),int(end*1./step)))

Respondido 06 Oct 12, 05:10

No parece funcionar correctamente, p. Ej. list(frange(99.8, 100.1, 0.1)) => [99.7, 99.80000000000001, 99.9] - Shai Coleman

@ShaiColeman Eso es redondeo de punto flotante general, no un defecto de este método en particular. Si le preocupa esto, varias respuestas aquí contienen soluciones alternativas; ver quizás también stackoverflow.com/questions/588004/… - triples

@tripleee, está mal incluso ignorar los errores de redondeo. esperado: [99.8, 99.9, 100.0] real: [99.7, 99.8, 99.9] - Shai Coleman

Sé que llego tarde a la fiesta aquí, pero aquí hay una solución generadora trivial que funciona en 3.6:

def floatRange(*args):
    start, step = 0, 1
    if len(args) == 1:
        stop = args[0]
    elif len(args) == 2:
        start, stop = args[0], args[1]
    elif len(args) == 3:
        start, stop, step = args[0], args[1], args[2]
    else:
        raise TypeError("floatRange accepts 1, 2, or 3 arguments. ({0} given)".format(len(args)))
    for num in start, step, stop:
        if not isinstance(num, (int, float)):
            raise TypeError("floatRange only accepts float and integer arguments. ({0} : {1} given)".format(type(num), str(num)))
    for x in range(int((stop-start)/step)):
        yield start + (x * step)
    return

entonces puedes llamarlo como el original range()... no hay manejo de errores, pero avíseme si hay un error que pueda ser detectado razonablemente y lo actualizaré. o puede actualizarlo. esto es StackOverflow.

Respondido el 02 de enero de 19 a las 21:01

Como advertencia, esta solución no implementa el __contains__ operador, y dependiendo de su caso de uso, podría ser MUY lento llamar if x in list(floatRange(a,b,c)):... - david culbreth

Agregue autocorrección para la posibilidad de un paso de inicio de sesión incorrecto:

def frange(start,step,stop):
    step *= 2*((stop>start)^(step<0))-1
    return [start+i*step for i in range(int((stop-start)/step))]

Respondido el 01 de diciembre de 10 a las 06:12

Mi solución:

def seq(start, stop, step=1, digit=0):
    x = float(start)
    v = []
    while x <= stop:
        v.append(round(x,digit))
        x += step
    return v

Respondido 06 Oct 12, 05:10

Solo soy un principiante, pero tuve el mismo problema, al simular algunos cálculos. Así es como intenté resolver esto, que parece funcionar con pasos decimales.

También soy bastante vago y me resultó difícil escribir mi propia función de rango.

Básicamente lo que hice fue cambiar mi xrange(0.0, 1.0, 0.01) a xrange(0, 100, 1) y usó la división por 100.0 dentro del bucle. También me preocupaba si habría errores de redondeo. Así que decidí probar, si hay alguno. Ahora escuché, que si por ejemplo 0.01 de un cálculo no es exactamente el flotador 0.01 compararlos debería devolver False (si me equivoco, hágamelo saber).

Así que decidí probar si mi solución funcionará para mi rango ejecutando una prueba corta:

for d100 in xrange(0, 100, 1):
    d = d100 / 100.0
    fl = float("0.00"[:4 - len(str(d100))] + str(d100))
    print d, "=", fl , d == fl

E imprimió True para cada uno.

Ahora, si me equivoco por completo, hágamelo saber.

Respondido 10 Oct 13, 23:10

El truco para evitar problema de redondeo es usar un número separado para moverse a través del rango, que comienza y la mitad el paso un paso al frente de comienzo.

# floating point range
def frange(a, b, stp=1.0):
  i = a+stp/2.0
  while i<b:
    yield a
    a += stp
    i += stp

Alternativamente, numpy.arange puede ser usado.

Respondido el 02 de Septiembre de 15 a las 11:09

Se puede hacer usando la biblioteca Numpy. La función arange () permite pasos en flotación. Pero, devuelve una matriz numerosa que se puede convertir a lista usando tolist () para nuestra conveniencia.

for i in np.arange(0, 1, 0.1).tolist():
   print i

Respondido 12 Feb 16, 12:02

Mi respuesta es similar a otros que usan map (), sin necesidad de NumPy y sin usar lambda (aunque podría). Para obtener una lista de valores flotantes de 0.0 a t_max en pasos de dt:

def xdt(n):
    return dt*float(n)
tlist  = map(xdt, range(int(t_max/dt)+1))

Respondido 16 Feb 17, 19:02

start y stop son inclusivos en lugar de uno u otro (generalmente se excluye el stop) y sin importaciones, y utilizando generadores

def rangef(start, stop, step, fround=5):
    """
    Yields sequence of numbers from start (inclusive) to stop (inclusive)
    by step (increment) with rounding set to n digits.

    :param start: start of sequence
    :param stop: end of sequence
    :param step: int or float increment (e.g. 1 or 0.001)
    :param fround: float rounding, n decimal places
    :return:
    """
    try:
        i = 0
        while stop >= start and step > 0:
            if i==0:
                yield start
            elif start >= stop:
                yield stop
            elif start < stop:
                if start == 0:
                    yield 0
                if start != 0:
                    yield start
            i += 1
            start += step
            start = round(start, fround)
        else:
            pass
    except TypeError as e:
        yield "type-error({})".format(e)
    else:
        pass


# passing
print(list(rangef(-100.0,10.0,1)))
print(list(rangef(-100,0,0.5)))
print(list(rangef(-1,1,0.2)))
print(list(rangef(-1,1,0.1)))
print(list(rangef(-1,1,0.05)))
print(list(rangef(-1,1,0.02)))
print(list(rangef(-1,1,0.01)))
print(list(rangef(-1,1,0.005)))
# failing: type-error:
print(list(rangef("1","10","1")))
print(list(rangef(1,10,"1")))

Python 3.6.2 (v3.6.2: 5fd33b5, 8 de julio de 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)]

respondido 01 mar '18, 21:03

Muchas de las soluciones aquí todavía tenían errores de punto flotante en Python 3.6 y no hicieron exactamente lo que yo personalmente necesitaba.

La función siguiente toma números enteros o flotantes, no requiere importaciones y no devuelve errores de punto flotante.

def frange(x, y, step):
    if int(x + y + step) == (x + y + step):
        r = list(range(int(x), int(y), int(step)))
    else:
        f = 10 ** (len(str(step)) - str(step).find('.') - 1)
        rf = list(range(int(x * f), int(y * f), int(step * f)))
        r = [i / f for i in rf]

    return r

Respondido 05 Feb 19, 18:02

Para contrarrestar los problemas de precisión de flotación, puede utilizar el Decimal módulo.

Esto exige un esfuerzo extra de conversión a Decimal de int or float mientras escribe el código, pero puede pasar str y modificar la función si ese tipo de conveniencia es realmente necesario.

from decimal import Decimal


def decimal_range(*args):

    zero, one = Decimal('0'), Decimal('1')

    if len(args) == 1:
        start, stop, step = zero, args[0], one
    elif len(args) == 2:
        start, stop, step = args + (one,)
    elif len(args) == 3:
        start, stop, step = args
    else:
        raise ValueError('Expected 1 or 2 arguments, got %s' % len(args))

    if not all([type(arg) == Decimal for arg in (start, stop, step)]):
        raise ValueError('Arguments must be passed as <type: Decimal>')

    # neglect bad cases
    if (start == stop) or (start > stop and step >= zero) or \
                          (start < stop and step <= zero):
        return []

    current = start
    while abs(current) < abs(stop):
        yield current
        current += step

Salidas de muestra -

from decimal import Decimal as D

list(decimal_range(D('2')))
# [Decimal('0'), Decimal('1')]
list(decimal_range(D('2'), D('4.5')))
# [Decimal('2'), Decimal('3'), Decimal('4')]
list(decimal_range(D('2'), D('4.5'), D('0.5')))
# [Decimal('2'), Decimal('2.5'), Decimal('3.0'), Decimal('3.5'), Decimal('4.0')]
list(decimal_range(D('2'), D('4.5'), D('-0.5')))
# []
list(decimal_range(D('2'), D('-4.5'), D('-0.5')))
# [Decimal('2'),
#  Decimal('1.5'),
#  Decimal('1.0'),
#  Decimal('0.5'),
#  Decimal('0.0'),
#  Decimal('-0.5'),
#  Decimal('-1.0'),
#  Decimal('-1.5'),
#  Decimal('-2.0'),
#  Decimal('-2.5'),
#  Decimal('-3.0'),
#  Decimal('-3.5'),
#  Decimal('-4.0')]

Respondido 02 ago 20, 16:08

Con similar Decimal insumos, np.arange funciona igual: np.arange(Decimal('-2.0'), Decimal('2.0'), Decimal('0.1')) - hpaulj

Sí, gracias. Aunque, eso necesitaría una lib externa (numpy). - shad0w_wa1k3r

Le agradecería si pudiera darnos su opinión o el motivo del voto negativo. - shad0w_wa1k3r

Las preguntas sobre votos negativos no tienen sentido, ya que los votantes no son notificados y, por lo tanto, rara vez los ven. Me notificaron en base a un comentario de hace 2 años. - hpaulj

Lamento haberte enviado un ping, espero que no sea así, ya que no etiqueté. Y sí, mi comentario fue esperanzador. - shad0w_wa1k3r

Aquí está mi solución que funciona bien con float_range (-1, 0, 0.01) y funciona sin errores de representación de punto flotante. No es muy rápido, pero funciona bien:

from decimal import Decimal

def get_multiplier(_from, _to, step):
    digits = []
    for number in [_from, _to, step]:
        pre = Decimal(str(number)) % 1
        digit = len(str(pre)) - 2
        digits.append(digit)
    max_digits = max(digits)
    return float(10 ** (max_digits))


def float_range(_from, _to, step, include=False):
    """Generates a range list of floating point values over the Range [start, stop]
       with step size step
       include=True - allows to include right value to if possible
       !! Works fine with floating point representation !!
    """
    mult = get_multiplier(_from, _to, step)
    # print mult
    int_from = int(round(_from * mult))
    int_to = int(round(_to * mult))
    int_step = int(round(step * mult))
    # print int_from,int_to,int_step
    if include:
        result = range(int_from, int_to + int_step, int_step)
        result = [r for r in result if r <= int_to]
    else:
        result = range(int_from, int_to, int_step)
    # print result
    float_result = [r / mult for r in result]
    return float_result


print float_range(-1, 0, 0.01,include=False)

assert float_range(1.01, 2.06, 5.05 % 1, True) ==\
[1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01, 2.06]

assert float_range(1.01, 2.06, 5.05 % 1, False)==\
[1.01, 1.06, 1.11, 1.16, 1.21, 1.26, 1.31, 1.36, 1.41, 1.46, 1.51, 1.56, 1.61, 1.66, 1.71, 1.76, 1.81, 1.86, 1.91, 1.96, 2.01]

Respondido el 08 de enero de 13 a las 21:01

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.