Comment utiliser une valeur de pas décimal ()?

y a-t-il un moyen de faire un pas entre 0 et 1 par 0.1?

j'ai pensé que je pouvais le faire comme suit, mais il a échoué:

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

au lieu de cela, il dit que l'argument de pas ne peut pas être zéro, ce que je ne m'attendais pas.

523
demandé sur martineau 2009-01-25 13:20:43

30 réponses

plutôt que d'utiliser un pas décimal directement, il est beaucoup plus sûr d'exprimer cela en termes de combien de points vous voulez. Autrement, une erreur d'arrondissement à virgule flottante est susceptible de donner un mauvais résultat.

vous pouvez utiliser la fonction linspace de la bibliothèque NumPy (qui ne fait pas partie de la bibliothèque standard mais est relativement facile à obtenir). linspace prend un certain nombre de points à retourner, et vous permet également de préciser si oui ou non inclure le droit d'extrémité:

>>> 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 vous voulez vraiment utiliser une valeur de pas à virgule flottante, vous pouvez, avec 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])

Floating-point de l'erreur d'arrondi sera cause des problèmes, cependant. Voici un cas simple où l'erreur d'arrondissement fait que arange produit un tableau de longueur-4 alors qu'il ne devrait produire que 3 Nombres:

>>> numpy.arange(1, 1.3, 0.1)
array([1. , 1.1, 1.2, 1.3])
655
répondu Andrew Jaffe 2018-08-10 20:48:28

python's range() ne peut faire que des entiers, pas des points flottants. Dans votre cas spécifique, vous pouvez utiliser une liste de compréhension à la place:

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

(remplacer l'appel à portée par cette expression.)

Pour le cas plus général, vous pouvez écrire une fonction personnalisée ou d'un générateur.

159
répondu 2009-01-25 10:35:25

en S'appuyant sur ' xrange ([start], stop [, step])' , vous pouvez définir un générateur qui accepte et produit n'importe quel type que vous choisissez (Coller aux types supportant + et < ):

>>> 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']
>>> 
139
répondu gimel 2009-01-25 11:57:17

augmente la magnitude de i pour la boucle et puis la réduire quand vous en avez besoin.

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

EDIT: honnêtement, je ne me souviens pas pourquoi j'ai pensé que cela fonctionnerait syntaxiquement

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

qui devrait avoir la sortie désirée.

31
répondu cmsjr 2015-02-01 20:26:14

scipy a une fonction intégrée arange qui généralise le range() constructeur de Python pour satisfaire votre exigence de la manipulation de flotteur.

from scipy import arange

21
répondu Catherine Ray 2014-05-17 20:50:03

num Py est un peu exagéré, je pense.

[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 général, pour faire un pas-by - 1/x jusqu'à y vous feriez

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 a produit moins de bruit d'arrondi lors de mes essais).

19
répondu Kalle 2017-02-28 02:06:20

similaire à la fonction R seq , celle-ci retourne une séquence dans n'importe quel ordre donné la valeur correcte de pas. La dernière valeur est égale à la valeur d'arrêt.

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([])

résultats

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]

seq(1, 1)

[1 ]

16
répondu zeferino 2018-02-03 09:38:14

la fonction range() intégrée retourne une séquence de valeurs entières, je le crains, donc vous ne pouvez pas l'utiliser pour faire un pas décimal.

je dirais juste utiliser une boucle de temps:

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

si vous êtes curieux, Python convertit votre 0.1 En 0, c'est pourquoi il vous dit que l'argument ne peut pas être zéro.

10
répondu Dana 2009-01-25 10:32:43
import numpy as np
for i in np.arange(0, 1, 0.1): 
    print i 
9
répondu Raja 2012-09-07 02:04:48

Voici une solution en utilisant itertools :

import itertools

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

Exemple D'Usage:

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

sortie:

0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
9
répondu Pramod 2015-03-18 13:36:50
[x * 0.1 for x in range(0, 10)] 

en python 2.7 x vous donne le résultat de:

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

mais si vous utilisez:

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

vous donne le désiré:

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

7
répondu Nik 2012-05-14 02:17:56

et si vous le faites souvent, vous pourriez vouloir sauvegarder la liste générée r

r=map(lambda x: x/10.0,range(0,10))
for i in r:
    print i
5
répondu RSabet 2009-01-25 10:48:33

mes versions utilisent la fonction de portée originale pour créer des indices multiplicatifs pour le décalage. Cela permet la même syntaxe à la fonction de portée originale. J'ai fait deux versions, l'une avec float, et L'autre avec Decimal, parce que j'ai trouvé que dans certains cas, je voulais éviter la dérive arrondie introduite par l'arithmétique flottante.

il est compatible avec les résultats des ensembles vides comme dans la gamme/xrange.

N'attribuant qu'une seule valeur numérique à l'une ou l'autre fonction renvoie la valeur de sortie de la plage standard à la valeur de plafond entière du paramètre d'entrée (donc si vous lui donnez 5.5, elle renvoie la plage(6).)

Edit: le code ci-dessous est maintenant disponible en paquet sur pypi: Franges

## 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)) # []
4
répondu Nisan.H 2012-12-18 22:57:31

C'est ma solution pour obtenir des gammes avec des pas de flotteur.

en utilisant cette fonction, il n'est pas nécessaire d'importer numpy, ni de l'installer.

je suis presque sûr qu'il pourrait être amélioré et optimisé. N'hésitez pas à le faire et à le poster ici.

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)

la sortie est:

[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]
4
répondu Carlos Vega 2013-12-12 17:04:50

more_itertools est une bibliothèque tierce partie qui met en œuvre un numeric_range outil:

import more_itertools as mit


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

sortie

0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9

cet outil fonctionne aussi pour Decimal et Fraction .

3
répondu pylang 2018-02-09 00:31:07

vous pouvez utiliser cette fonction:

def frange(start,end,step):
    return map(lambda x: x*step, range(int(start*1./step),int(end*1./step)))
2
répondu user376536 2012-10-06 04:39:29

Le truc pour éviter de arrondi problème est d'utiliser un numéro distinct pour vous déplacer dans la gamme, qui commence et moitié le étape devant démarrer .

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

alternativement, numpy.arange peut être utilisé.

2
répondu wolfram77 2015-09-02 10:15:29

pour l'exhaustivité de boutique, une solution fonctionnelle:

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)
2
répondu Bijou Trouvaille 2015-09-12 07:44:22

il peut être fait en utilisant la bibliothèque Numpy. la fonction arange () permet des pas dans float. Mais il renvoie un tableau numpy qui peut être converti en list en utilisant tolist() pour notre commodité.

for i in np.arange(0, 1, 0.1).tolist():
   print i
2
répondu user3654478 2016-02-12 12:18:12

ma réponse est similaire à d'autres en utilisant map(), sans besoin de num Py, et sans utiliser lambda (bien que vous pourriez). Pour obtenir une liste des valeurs de float de 0.0 à t_max par étapes de dt:

def xdt(n):
    return dt*float(n)
tlist  = map(xdt, range(int(t_max/dt)+1))
2
répondu Eric Myers 2017-02-16 19:48:03

ajouter correction automatique pour la possibilité d'un signe incorrect sur l'étape:

def frange(start,step,stop):
    step *= 2*((stop>start)^(step<0))-1
    return [start+i*step for i in range(int((stop-start)/step))]
1
répondu BobH 2010-12-01 06:36:16

ma solution:

def seq(start, stop, step=1, digit=0):
    x = float(start)
    v = []
    while x <= stop:
        v.append(round(x,digit))
        x += step
    return v
1
répondu Jjen 2012-10-06 04:59:27
"151960920 de la" Meilleure Solution: aucune erreur d'arrondi

_________________________________________________________________________________

>>> 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]

_________________________________________________________________________________



Ou, pour une plage définie au lieu de points de données définis (par exemple fonction continue), utiliser:

>>> 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]

pour mettre en œuvre une fonction: Remplacer x / pow(step, -1) par f( x / pow(step, -1) ) , et définir f .

Par exemple:

>>> 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]
1
répondu Jason 2016-12-10 19:36:46

le démarrage et l'arrêt inclusive plutôt que l'un ou l'autre (généralement arrêt est exclu) et sans les importations, et à l'aide de générateurs

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, Jul 8 2017, 04:57:36) [MSC v. 1900 64 bit (AMD64)]

1
répondu Goran B. 2018-03-01 21:53:28

personne N'a encore mentionné la solution recommandée dans le Python 3 docs :

voir aussi:

  • la recette de linspace montre comment mettre en œuvre une version paresseuse de la gamme qui convient aux applications de point flottant.

une fois définie, la recette est facile à utiliser et ne nécessite pas numpy ou toute autre bibliothèque externe, mais fonctionne comme numpy.linspace() . Notez que plutôt qu'un argument step , le troisième argument num spécifie le nombre de valeurs désirées, par exemple:

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

je cite une version modifiée de la recette complète de Python 3 D'Andrew Barnert ci-dessous:

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))
1
répondu Chris_Rands 2018-03-03 08:24:08

pour contrer les problèmes de précision du flotteur, vous pouvez utiliser le Decimal module .

cela demande un effort supplémentaire de convertir en Decimal de int ou float en écrivant le code, mais vous pouvez passer str et modifier la fonction si ce genre de convenance est en effet nécessaire.

from decimal import Decimal
from decimal import Decimal as D


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
"151970920 de l'Échantillon" sorties

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')]
1
répondu shad0w_wa1k3r 2018-03-04 13:05:11

voici ma solution qui fonctionne bien avec float_range (-1, 0, 0.01) et fonctionne sans erreurs de représentation en virgule flottante. Il n'est pas très rapide, mais fonctionne très 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]
0
répondu pymen 2013-01-08 21:21:33

je suis seulement un débutant, mais j'ai eu le même problème, en simulant quelques calculs. Voici comment j'ai essayé d'en arriver là, ce qui semble fonctionner avec des pas décimaux.

je suis également assez paresseux et j'ai donc eu du mal à écrire ma propre fonction de gamme.

fondamentalement, ce que j'ai fait est changé mon xrange(0.0, 1.0, 0.01) en xrange(0, 100, 1) et utilisé la division par 100.0 à l'intérieur de la boucle. Je m'inquiétais aussi de savoir s'il y aurait des erreurs d'arrondissement. J'ai donc décidé de tester, si il y a de tout. Maintenant j'ai entendu, que si par exemple 0.01 d'un calcul n'est pas exactement le flotteur 0.01 les comparant devrait retourner False (si je me trompe, s'il vous plaît laissez-moi savoir).

donc j'ai décidé de tester si ma solution fonctionnera pour ma gamme en lançant un test court:

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

et il a imprimé True pour chacun.

maintenant, si je me trompe totalement, s'il vous plaît faites le moi savoir.

0
répondu user2836437 2013-10-10 22:27:18

cette doublure ne va pas encombrer votre code. Le signe du paramètre step est important.

def frange(start, stop, step):
    return [x*step+start for x in range(0,round(abs((stop-start)/step)+0.5001),
        int((stop-start)/step<0)*-2+1)]
0
répondu Tjaart 2013-11-21 07:37:29

frange(début, fin, précision)

def frange(a,b,i):
    p = 10**i
    sr = a*p
    er = (b*p) + 1
    p = float(p)
    return map(lambda x: x/p, xrange(sr,er))

In >frange(-1,1,1)

Out>[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
0
répondu zred 2014-07-10 18:15:39