web-dev-qa-db-fra.com

Comment incrémenter nombre de 0.01 en javascript à l'aide d'une boucle?

Problème

J'essayais de dresser une liste de hauteurs dans la console par mètres à partir de 1,20 m et se terminant à 2,50 m.

J'ai utilisé ce code:

var heights = [];
for ( var i=1.20, l=2.5; i<l; i+=0.01 ){

    heights.Push(i);

}

heights = heights.join('\n');

Si je console.log( heights ) je reçois:

1.2
1.21
1.22
1.23
...

Mais à 1,37, je commence à obtenir:

1.37
1.3800000000000001
1.3900000000000001
1.4000000000000001
1.4100000000000001
1.4200000000000002
1.4300000000000002

Des questions

  • Que se passe-t-il?
  • Comment je le répare?

Démo

Voici a demo si vous êtes trop paresseux pour le taper dans votre console :-)

22
hitautodestruct

Vous faites ça bien. Le problème vient de l'inexactitude des nombres en virgule flottante.

Pourquoi les nombres en virgule flottante sont-ils si inexacts?

Si vous souhaitez afficher ce numéro, utilisez:

heights[i].toFixed(2);

Notez que toFixed() renvoie une chaîne et que vous devrez reconvertir en float (parseFloat()) si vous souhaitez effectuer davantage d'opérations numériques.

15
George Reith

C’est justement à cause de la façon dont les mathématiques fonctionnent en JavaScript que vous pouvez trouver une foule de réponses explicatives à ce sujet - comme ceci un. La solution la plus simple consiste à tout faire par 100, puis de diviser en ajoutant au tableau par exemple.

var heights = [], i, l;
for (i = 120; i < 250; i += 1){    
    heights.Push(i / 100);    
}

Vous pouvez utiliser toFixed mais cela vous donnera une String comme résultat.

8
phenomnomnominal

Cela est dû au fait que les nombres à virgule flottante sont stockés en interne, ce n'est pas spécifique à JavaScript. Vous pouvez utiliser .toFixed() pour stocker une représentation sous forme de chaîne du nombre avec la précision souhaitée. Ainsi:

heights.Push(i.toFixed(2));

Si vous souhaitez éviter de stocker des chaînes, puis de les reconvertir en un nombre réel, vous pouvez multiplier l'étape pour qu'il devienne un nombre entier, puis stocker une division:

for (var i = 120; i <= 250; ++i) {
    heights.Push(i / 100);
}

La différence, à part le fait que vous avez maintenant des chiffres, est que plusieurs de 0.1 sont représentés avec une précision unique, par exemple. 2.4 au lieu de "2.40".

2
Ja͢ck

En effet, les machines utilisent la base 2 et vous utilisez des nombres de la base 10 qui ne peuvent pas être représentés avec précision en base 2 avec un nombre à virgule flottante.

Vous pouvez utiliser cette bibliothèque pour la formater: https://github.com/dtrebbien/BigDecimal.js

1
Red Alert

Comme il a été mentionné, toFixed () renvoie String, et parseFloat () convertis String en Float. parseFloat() supprime également les zéros de fin, ce qui est logique, mais ne fonctionnait pas pour mon cas d'utilisation.

Voici un exemple d'itération utilisant Float et conservant les zéros de fin. 

var i = 0.9,
  floats = [];

while (i < 2) {
  i = (i + 0.1).toFixed(1);
  floats.Push(i);
  i = parseFloat(i);
}
console.log(floats);


[ '1.0',
  '1.1',
  '1.2',
  '1.3',
  '1.4',
  '1.5',
  '1.6',
  '1.7',
  '1.8',
  '1.9',
  '2.0' ]

Si les zéros à la fin ne sont pas nécessaires, la boucle peut être simplifiée comme suit:

while (i < 2) {
  floats.Push(i);
  i = parseFloat((i + 0.1).toFixed(1));
}
1
Vadym Tyemirov

Utilisez la méthode toFixed (float) pour limiter le nombre de chiffres après la virgule.

heights.Push(i.toFixed(2));
0
mcamier