840 votes

Solution élégante pour JavaScript variable point problème numéro

J'ai le texte suivant mannequin script de test:

function test(){
    var x = 0.1 * 0.2;
    document.write(x);
}
test();

Cela permettra d'imprimer le résultat 0.020000000000000004 alors qu'il aurait suffit d'imprimer 0.02 (si vous utilisez votre calculatrice). Que j'ai compris c'est en raison d'erreurs en virgule flottante, la multiplication de précision.

Quelqu'un aurait-il une bonne solution, de sorte que, dans ce cas j'obtiens le bon résultat 0.02? Je sais qu'il y a des fonctions comme toFixed ou de l'arrondissement serait une autre possibilité, mais que j'aimerais c'est vraiment l'ensemble du numéro imprimé de coupe et d'arrondi. Je voulais juste savoir si l'un de vous a quelques belle, élégante solution.

Bien sûr, sinon, je vais arrondir à 10 chiffres.

607voto

Michael Borgwardt Points 181658

À partir de la virgule Flottante Guide:

Que puis-je faire pour éviter ce problème?

Cela dépend de quel type de les calculs que vous faites.

  • Si vous avez vraiment besoin de vos résultats à atteindre exactement, surtout quand vous travailler avec de l'argent: à l'aide d'un décimal type de données.
  • Si vous ne voulez pas voir toutes ces décimales: il suffit de format votre résultat arrondi à un fixe nombre de décimales lorsque affichant.
  • Si vous n'avez pas de décimal de type de données disponible, une alternative est de travailler avec des entiers, par exemple, faire de l'argent les calculs entièrement en cents. Mais c'est plus de travail et a quelques les inconvénients.

Notez que le premier point ne s'applique que si vous avez vraiment besoin de précision décimale de comportement. La plupart des gens n'en avez pas besoin, ils sont juste irrité que leurs programmes ne fonctionnent pas correctement avec de tels chiffres 1/10 sans se rendre compte qu'ils ne seraient même pas clignoter à l'erreur même si elle s'est produite avec 1/3.

Si le premier point s'applique vraiment à vous, utilisez BigDecimal pour JavaScript, ce qui n'est pas élégant du tout, mais en fait de résoudre le problème plutôt que de fournir une solution imparfaite.

196voto

linux_mike Points 449

J’ai comme solution de Pedro Ladaria et utiliser quelque chose de similaire.

À la différence de Pedros solution que cela va arrondir à 0,999... répétant et est précise à plus/moins, un sur le chiffre le moins significatif.

95voto

Nirk Points 9999

Pour mathématiquement incliné: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

L'approche recommandée consiste à utiliser les facteurs de correction (multiplier par une puissance convenable de 10, de sorte que le arithmétiques entre les nombres entiers). Par exemple, dans le cas d' 0.1 * 0.2, le facteur de correction est - 10, et que vous effectuez le calcul:

> var x = 0.1
> var y = 0.2
> var cf = 10
> x * y
0.020000000000000004
> (x * cf) * (y * cf) / (cf * cf)
0.02

Un (très rapide) de la solution ressemble à quelque chose comme:

var _cf = (function() {
  function _shift(x) {
    var parts = x.toString().split('.');
    return (parts.length < 2) ? 1 : Math.pow(10, parts[1].length);
  }
  return function() { 
    return Array.prototype.reduce.call(arguments, function (prev, next) { return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); }, -Infinity);
  };
})();

Math.a = function () {
  var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
  function cb(x, y, i, o) { return x + f * y; }
  return Array.prototype.reduce.call(arguments, cb, 0) / f;
};

Math.s = function (l,r) { var f = _cf(l,r); return (l * f - r * f) / f; };

Math.m = function () {
  var f = _cf.apply(null, arguments);
  function cb(x, y, i, o) { return (x*f) * (y*f) / (f * f); }
  return Array.prototype.reduce.call(arguments, cb, 1);
};

Math.d = function (l,r) { var f = _cf(l,r); return (l * f) / (r * f); };

Dans ce cas:

> Math.m(0.1, 0.2)
0.02

Je vous recommande vraiment de l'aide d'un testé bibliothèque comme SinfulJS

57voto

Nate Zaugg Points 1969

Vous effectuez uniquement multiplication ? Si oui alors vous pouvez utiliser à votre avantage un secret soigné sur l’arithmétique décimale. C’est que c’est à dire que si nous avez puis nous savons qu’il y aura 5 décimales parce que a 3 décimales et a deux. Donc si JavaScript nous a donné un numéro comme `` nous pouvons en toute sécurité tronquer à la 5ème décimale sans craindre de perdre la précision.

31voto

Douglas Points 10417

Vous êtes à la recherche d'un sprintf de la mise en œuvre de JavaScript, de sorte que vous pouvez écrire des chars avec de petites erreurs en eux (puisqu'ils sont stockés dans le format binaire) dans un format que vous attendez.

Essayez javascript-sprintf, vous serait-il appeler comme ceci:

var yourString = sprintf("%.2f", yourNumber);

pour imprimer votre numéro comme un float avec deux décimales.

Vous pouvez également utiliser le Numéro.toFixed() pour l'affichage, si vous préférez ne pas inclure plus de fichiers simplement pour floating point d'arrondi à une précision donnée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X