La documentation dit fondamentalement que range
doit se comporter exactement comme cette implémentation (pour positif step
):
def range(start, stop, step):
x = start
while True:
if x >= stop: return
yield x
x += step
Il dit également que ses arguments doivent être des entiers. Pourquoi donc? Cette définition n'est-elle pas également parfaitement valable si l'étape est un flotteur?
Dans mon cas, je suis esp. ayant besoin d'une fonction range
qui accepte un type flottant comme argument step
. Y en a-t-il dans Python ou dois-je implémenter le mien?
Plus spécifique: Comment pourrais-je traduire ce code C directement en Python d'une manière agréable (c'est-à-dire ne pas simplement le faire via une boucle while
- manuellement)):
for(float x = 0; x < 10; x += 0.5f) { /* ... */ }
Vous pouvez utiliser numpy.arange
.
EDIT: Les documents préfèrent numpy.linspace
. Merci @Droogans d'avoir remarqué =)
Une explication pourrait être les problèmes d'arrondi à virgule flottante. Par exemple, si vous pouviez appeler
range(0, 0.4, 0.1)
vous pourriez vous attendre à une sortie de
[0, 0.1, 0.2, 0.3]
mais vous obtenez en fait quelque chose comme
[0, 0.1, 0.2000000001, 0.3000000001]
en raison de problèmes d'arrondi. Et comme la plage est souvent utilisée pour générer des indices d'une certaine sorte, il s'agit uniquement d'entiers.
Pourtant, si vous voulez un générateur de portée pour les flotteurs, vous pouvez simplement lancer le vôtre.
def xfrange(start, stop, step):
i = 0
while start + i * step < stop:
yield start + i * step
i += 1
Afin de pouvoir utiliser des nombres décimaux dans une expression de plage, une manière intéressante de le faire est la suivante: [x * 0,1 pour x dans la plage (0, 10)]
Le problème avec la virgule flottante est que vous ne pouvez pas obtenir le même nombre d'éléments que prévu, en raison de l'inexactitude. Cela peut être un vrai problème si vous jouez avec des polynômes où le nombre exact d'éléments est assez important.
Ce que vous voulez vraiment, c'est une progression arithmétique; le code suivant fonctionnera très bien pour int
, float
et complex
... et les chaînes et les listes ...
def arithmetic_progression(start, step, length):
for i in xrange(length):
yield start + i * step
Notez que ce code a de meilleures chances que votre dernière valeur se situe dans le rugissement d'un taureau de la valeur attendue que toute alternative qui maintient un total cumulé.
>>> 10000 * 0.0001, sum(0.0001 for i in xrange(10000))
(1.0, 0.9999999999999062)
>>> 10000 * (1/3.), sum(1/3. for i in xrange(10000))
(3333.333333333333, 3333.3333333337314)
Correction: voici un gadget concurrentiel total cumulé :
def kahan_range(start, stop, step):
assert step > 0.0
total = start
compo = 0.0
while total < stop:
yield total
y = step - compo
temp = total + y
compo = (temp - total) - y
total = temp
>>> list(kahan_range(0, 1, 0.0001))[-1]
0.9999
>>> list(kahan_range(0, 3333.3334, 1/3.))[-1]
3333.333333333333
>>>
Lorsque vous ajoutez des nombres à virgule flottante, il y a souvent une petite erreur. Une range(0.0, 2.2, 1.1)
renverrait-elle [0.0, 1.1]
ou [0.0, 1.1, 2.199999999]
? Il n'y a aucun moyen d'être certain sans une analyse rigoureuse.
Le code que vous avez publié est une solution de contournement correcte si vous en avez vraiment besoin. Soyez juste conscient des lacunes possibles.
Voici un cas particulier qui pourrait suffire:
[ (1.0/divStep)*x for x in range(start*divStep, stop*divStep)]
Dans votre cas, ce serait:
#for(float x = 0; x < 10; x += 0.5f) { /* ... */ } ==>
start = 0
stop = 10
divstep = 1/.5 = 2 #This needs to be int, thats why I said 'special case'
et donc:
>>> [ .5*x for x in range(0*2, 10*2)]
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5]
Voici ce que j'utiliserais:
numbers = [float(x)/10 for x in range(10)]
plutôt que:
numbers = [x*0.1 for x in range(10)]
that would return :
[0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9]
j'espère que ça aide.