Maison  >  Article  >  interface Web  >  Solution à l'erreur de calcul corrigée en Javascript

Solution à l'erreur de calcul corrigée en Javascript

黄舟
黄舟original
2017-08-22 10:40:211930parcourir

Cet article présente principalement la solution à l'erreur de calcul toFixed en Javascript (le défaut de s'appuyer sur la méthode d'arrondi du banquier). Les amis dans le besoin peuvent s'y référer

Avant-propos

Dans le projet d'entreprise, un module impliquant un grand nombre de calculs de prix à virgule flottante était impliqué, ce qui a déclenché en moi une série de réflexions :

Le problème du manque de la précision du calcul des nombres à virgule flottante dans l'environnement binaire informatique


console.log(.1+.2);
0.30000000000000004
Afin de résoudre le problème ci-dessus, la méthode toFixed a été utilisée, mais une erreur d'arrondi ; s'est produit dans lequel la décimale du nombre à virgule flottante se terminait par 5


var num = 0.045;
console.log(num.toFixed(2));
0.04
Cela a commencé comme point de départ pour moi pour mener une série d'explorations sur toFixed, et j'ai finalement trouvé quelques informations utiles. Les règles de calcul utilisées par toFixed sont :

Arrondi du banquier : La méthode d'arrondi dite du banquier est essentiellement une méthode d'arrondi à cinq et de départ pair (également connu sous le nom d'arrondi à cinq). et partant même).


Pour faire simple : pensez à arrondir à cinq. Si le nombre après cinq n'est pas zéro, ajoutez un. Si le nombre après cinq est zéro, regardez le nombre impair ou pair. le nombre avant cinq est pair, il doit être écarté. Si le nombre avant cinq est impair, il doit être arrondi à un.

Texte

Ensuite, nous vérifierons cette méthode d'arrondi dite du banquier. La vérification est divisée en trois situations, avec 4, 5 et 6 comme méthodes d'arrondi. . Confirmation des bits toFixed (en prenant chrome comme exemple) :

avec 4 comme bit d'arrondi :


var num = 0.004;
console.log(num.toFixed(2));
0.00
var num = 0.014;
console.log(num.toFixed(2));
0.01
var num = 0.094;
console.log(num.toFixed(2));
0.09
. en 4. Fin : Dans ce cas, toFixed fonctionne plutôt bien et il n'y a aucune erreur.

Utilisez 6 comme chiffre d'arrondi :


var num = 0.006;
console.log(num.toFixed(2));
0.01
var num = 0.016;
console.log(num.toFixed(2));
0.02
var num = 0.096;
console.log(num.toFixed(2));
0.10
Terminez par 6. Dans ce cas, toFixed se comporte Pas mal, pas de problème de bug.

Arrondi à 5 :

Différent de zéro après 5 :



var num = 0.0051;
console.log(num.toFixed(2));
0.01
var num = 0.0052;
console.log(num.toFixed(2));
0.01
var num = 0.0059;
console.log(num.toFixed(2));
0.01
Selon les règles, si le nombre après cinq n'est pas zéro, alors un sera avancé. Nous avons confirmé qu'il n'y a pas de problème.

Utiliser 5 comme chiffre d'arrondi :

Le nombre après 5 est zéro : Cette situation étant assez particulière, il s'agit d'une erreur de calcul dans le toFixed méthode, j'ai donc effectué de nombreuses confirmations et les ai testées dans les navigateurs grand public courants :


Prenons les cas de test suivants comme exemple :



var num = 0.005;
console.log(num.toFixed(2));
var num = 0.015;
console.log(num.toFixed(2));
var num = 0.025;
console.log(num.toFixed(2));
var num = 0.035;
console.log(num.toFixed(2));
var num = 0.045;
console.log(num.toFixed(2));
var num = 0.055;
console.log(num.toFixed(2));
var num = 0.065;
console.log(num.toFixed(2));
var num = 0.075;
console.log(num.toFixed(2));
var num = 0.085;
console.log(num.toFixed(2));
var num = 0.095;
console.log(num.toFixed(2));
Les résultats pour Chrome, Firefox, Safari et Opera sont les suivants :

0,01

0,01
0,03
0,04
0,04
0,06
0,07
0,07
0,09
0,10

les résultats ie11 sont les suivants :


0,01

0,02
0,03
0.04
0.05
0.06
0.07
0.08
0.09
0.10

On voit que c'est normal sous Ie11, mais des erreurs se produisent dans d'autres navigateurs. Bien qu'il ne respecte pas totalement les règles de la méthode d'arrondi bancaire, je pense que c'est à cause des pièges des nombres à virgule flottante en binaire qu'il ne respecte pas totalement cette règle.


En bref : que toFixed soit introduit pour résoudre le problème du manque de précision dans les calculs à virgule flottante, ou qu'il utilise la méthode d'arrondi du banquier, tout cela vise à résoudre le problème de précision, mais il ne peut pas être séparé de l'environnement à virgule flottante du système binaire, mais au moins cela nous a aidé à trouver le problème et nous a donné une solution.

Solution

Ci-dessous, je propose une méthode en remplaçant toFixed :



 Number.prototype.toFixed = function(length)
    {
      var carry = 0; //存放进位标志
      var num,multiple; //num为原浮点数放大multiple倍后的数,multiple为10的length次方
      var str = this + ''; //将调用该方法的数字转为字符串
      var dot = str.indexOf("."); //找到小数点的位置
      if(str.substr(dot+length+1,1)>=5) carry=1; //找到要进行舍入的数的位置,手动判断是否大于等于5,满足条件进位标志置为1
      multiple = Math.pow(10,length); //设置浮点数要扩大的倍数
      num = Math.floor(this * multiple) + carry; //去掉舍入位后的所有数,然后加上我们的手动进位数
      var result = num/multiple + ''; //将进位后的整数再缩小为原浮点数
      /*
      * 处理进位后无小数
      */
      dot = result.indexOf(".");
      if(dot < 0){
        result += &#39;.&#39;;
        dot = result.indexOf(".");
      }
      /*
      * 处理多次进位
      */
      var len = result.length - (dot+1);
      if(len < length){
        for(var i = 0; i < length - len; i++){
          result += 0;
        }
      }
      return result;
    }
L'idée générale de cette méthode est de trouver d'abord le bit d'arrondi, de déterminer si la position est supérieure ou égale à 5, d'arrondir manuellement un bit si la condition est remplie, puis d'utiliser le paramètre taille pour amplifiez le nombre à virgule flottante d'origine par le paramètre exponentiel times de 10 , puis utilisez floor pour supprimer tous les chiffres, y compris le bit d'arrondi, et déterminez s'il faut effectuer le report en fonction de notre précédent report manuel.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn