Pour le code ci-dessous, je veux que la plage s'arrête à la valeur 1.0, mais elle continue à monter jusqu'à 1.099999 ..., ce qui a du sens car c'est une valeur flottante.

Quelle serait la meilleure façon de créer cette plage avec un pas de 0,1?

import numpy as np

start = 0.5
stop = 1.0
step = 0.1

for parameter_value in np.arange(start, stop + step, step):
  print(parameter_value)

Production

0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999
1.0999999999999999
1
vibhud 6 oct. 2020 à 01:47

2 réponses

Meilleure réponse

Vous ne pouvez pas représenter 0,1 exactement au format binaire IEEE 754, qui est ce que la plupart des architectures modernes utiliser en interne pour représenter des nombres à virgule flottante.

La valeur binaire la plus proche de 0,1 n'est qu'une ombre sous la vérité. Lorsque vous ajoutez cette approximation la plus proche cinq fois, l'erreur augmente.

Selon la documentation de np.arange:

Lorsque vous utilisez une étape non entière, telle que 0,1, les résultats ne seront souvent pas cohérents. Il est préférable d'utiliser numpy.linspace pour ces cas.

La raison en est qu'en serrant les extrémités, linapace peut donner des assurances sur l'erreur cumulative que arange ne peut pas. Chaque étape individuelle utilisée par linspace peut ne pas être la représentation binaire la plus proche de 0,1, mais chaque élément sera aussi proche que possible de n * 0.1 depuis le début et la fin.

L'appel linapace correspondant à np.arange(0.5, 1.1, 0.1) est

np.linspace(0.5, 1.0, 6)

L'autre avantage de linspace est que vous fixez le nombre de points. Toujours selon la documentation arange (la valeur de retour):

Pour les arguments à virgule flottante, la longueur du résultat est ceil((stop - start)/step). En raison d'un débordement en virgule flottante, cette règle peut entraîner le fait que le dernier élément de out soit supérieur à stop .

1
Mad Physicist 6 oct. 2020 à 03:17

Comme alternative, vous pouvez utiliser le fait que la division n'entraîne pas autant d'erreur que l'ajout itéré. C'est aussi précis que l'arithmétique en virgule flottante peut vous apporter:

np.arange(5, 11) / 10.0
# => array([0.5, 0.6, 0.7, 0.8, 0.9, 1. ])

(np.linspace utilise une formule très similaire, mais tant que vous travaillez avec des nombres rationnels, le code ci-dessus peut être plus facile à comprendre dans votre cas d'utilisation - vous n'avez pas à calculer vous-même le nombre d'étapes.)

1
Amadan 6 oct. 2020 à 03:23