Maison >interface Web >js tutoriel >Number (). Tofixed () Erreurs d'arrondi: cassé mais réparable
Cet article a été initialement publié sur le blog de David Kaye
J'ai trouvé des erreurs d'arrondi dans le nombre (). Tofixed () dans tous les environnements JavaScript que j'ai essayés (Chrome, Firefox, Internet Explorer, Brave et Node.js). Étonnamment, le correctif est très simple. Continuez à lire ...
Lors de la modification d'une fonction de formatage numérique qui remplit la même fonction que intl.numberformat # format (), j'ai trouvé une erreur d'arrondi dans cette version dans tofixed ().
<code class="language-javascript">(1.015).toFixed(2) // 返回 "1.01" 而不是 "1.02"</code>
Le test échoué est situé à la ligne 42 ici. Je ne l'ai pas trouvé avant décembre 2017, ce qui m'a incité à vérifier d'autres problèmes.
Voir mon tweet sur cette question:
Il y a un long historique de rapports d'erreurs lors de l'utilisation de TofixEd ().
Voici quelques petits exemples de problèmes de stackOverflow à propos de ce problème:
Habituellement, ceux-ci indiquent a a erreurs d'une valeur , mais aucune plage ou modèle de valeurs qui renvoie le résultat d'erreur (au moins je ne l'ai pas trouvé , J'ai peut-être manqué quelque chose). Cela permet aux programmeurs de se concentrer sur de petits problèmes et de ne pas voir de modèles plus grands. Je ne leur en blâme pas.
Les résultats inattendus basés sur l'entrée doivent provenir du mode partagé dans l'entrée. Ainsi, au lieu de revoir la spécification de Number (). Tofixed (), je me suis concentré sur le test avec une série de valeurs pour déterminer où les erreurs apparaissent dans chaque série.
J'ai créé la fonction de test suivante pour effectuer une opération TofixEd () sur une série d'entiers de 1 à maxvalue, ajoutant une décimale de .005 à chaque entier. Le paramètre fixe (chiffre numérique) de tofixed () est calculé en fonction de la longueur de la valeur décimale.
<code class="language-javascript">(1.015).toFixed(2) // 返回 "1.01" 而不是 "1.02"</code>
L'exemple suivant effectue une opération sur les entiers 1 à 128, ajoute une décimale .015 pour chaque entier et renvoie un tableau de résultats "inattendu". Chaque résultat contient des champs donnés, attendus et réels. Ici, nous utilisons ce tableau et imprimons chaque élément.
<code class="language-javascript">function test({fraction, maxValue}) { fraction = fraction.toString() var fixLength = fraction.split('.')[1].length - 1 var last = Number(fraction.charAt(fraction.length - 1)) var fixDigit = Number(fraction.charAt(fraction.length - 2)) last >= 5 && (fixDigit = fixDigit + 1) var expectedFraction = fraction.replace(/[\d]{2,2}$/, fixDigit) return Array(maxValue).fill(0) .map(function(ignoreValue, index) { return index + 1 }) .filter(function(integer) { var number = integer + Number(fraction) var actual = number.toFixed(fixLength) var expected = Number(number + '1').toFixed(fixLength) return expected != actual }) .map(function(integer) { var number = Number(integer) + Number(fraction) return { given: number.toString(), expected: (Number(integer.toFixed(0)) + Number(expectedFraction)).toString(), actual: number.toFixed(fixLength) } }) }</code>
Pour cette situation, il y a 6 résultats inattendus.
<code class="language-javascript">test({ fraction: .015, maxValue: 128 }) .forEach(function(item) { console.log(item) })</code>
J'ai trouvé que cette erreur contient trois parties:
Par exemple, pour les entiers 1 à 128, (valeur) .tofixée (2) utilise des 3 décimales différentes se terminant par 5, ce qui entraîne les résultats suivants:
Ceux qui en savent plus sur les mathématiques binaires et à points flottants que moi pourra peut déduire la cause profonde. Je laisse ceci au lecteur comme un exercice.
Fixé par Plus d'une décimale pour corriger la valeur est toujours arrondie correctement; par exemple, (1.0151). Le test et le polyfill utilisent ces connaissances pour les contrôles d'exactitude.
Cela signifie que toutes les implémentations Tofixed () ont une solution simple: si la valeur contient une décimale, ajoutez "1" à la fin de la version de chaîne de la valeur à modifier. Cela peut ne pas être "conforme aux spécifications", mais cela signifie que nous obtiendrons les résultats attendus sans avoir à revisiter le niveau inférieur des opérations binaires ou de points flottants.
Avant que toutes les implémentations ne soient modifiées, si vous êtes prêt à le faire (tout le monde ne le veut pas), vous pouvez remplacer Tofixed () avec le polyfill suivant.
<code>Object { given: "1.015", expected: "1.02", actual: "1.01" } Object { given: "4.015", expected: "4.02", actual: "4.01" } Object { given: "5.015", expected: "5.02", actual: "5.01" } Object { given: "6.015", expected: "6.02", actual: "6.01" } Object { given: "7.015", expected: "7.02", actual: "7.01" } Object { given: "128.015", expected: "128.02", actual: "128.01" }</code>
Ensuite, exécutez à nouveau le test et vérifiez si la longueur du résultat est nulle.
<code class="language-javascript">(1.005).toFixed(2) == "1.01" || (function(prototype) { var toFixed = prototype.toFixed prototype.toFixed = function(fractionDigits) { var split = this.toString().split('.') var number = +(!split[1] ? split[0] : split.join('.') + '1') return toFixed.call(number, fractionDigits) } }(Number.prototype));</code>
ou exécutez simplement la conversion initiale qui démarre cet article.
<code class="language-javascript">test({ fraction: .0015, maxValue: 516 }) // Array [] test({ fraction: .0015, maxValue: 516 }).length // 0</code>
Merci d'avoir lu!
La méthode Number.tofixed () dans JavaScript est utilisée pour formater les nombres en utilisant la notation à point fixe. Il renvoie une représentation de chaîne d'un nombre qui n'utilise pas de représentation exponentielle et a exactement le nombre spécifié de chiffres après le point décimal. Si nécessaire, le nombre est arrondi et la chaîne de résultat a un point décimal après la longueur.
En raison de la façon dont JavaScript gère les nombres de points flottants binaires, la méthode Number.tofixed () donne parfois des résultats inexacts. JavaScript utilise des nombres de points flottants binaires, qui ne peuvent pas représenter avec précision toutes les décimales. Cette inexactitude peut conduire à des résultats inattendus lorsque le nombre est arrondi à un nombre décimal spécifique en utilisant la méthode Number.tofixed ().
Une façon de corriger les erreurs d'arrondi dans Number.tofixed () est d'utiliser une fonction d'arrondi personnalisée. Cette fonction peut prendre en compte les caractéristiques du traitement numérique de JavaScript et fournir des résultats plus précis. Par exemple, vous pouvez utiliser une fonction qui multiplie le nombre par une puissance de 10, le tourne vers l'entier le plus proche et le divise par la même puissance de 10.
Non, la méthode Number.tofixed () ne peut être utilisée qu'avec des valeurs numériques. Si vous essayez de l'utiliser avec une valeur non numérique, JavaScript lancera un type EERROR. Si vous devez utiliser cette méthode avec une valeur qui peut ne pas être un nombre, vous devez d'abord vérifier si la valeur est un nombre.
nombre.tofixed () et d'autres méthodes d'arrondi est généralement négligeable. Cependant, si vous effectuez beaucoup d'opérations, l'utilisation d'une fonction d'arrondi personnalisée peut être légèrement plus rapide que d'utiliser la méthode numéro.tofixed ().
Non, la méthode Number.tofixed () ne peut qu'arrondir à un maximum de 20 décimales. Si vous essayez de contourner à plus de 20 décimales, JavaScript lancera un RangeError.
Number.tofixed () La méthode gère les nombres négatifs de la même manière que les nombres positifs. Il arrond la valeur absolue du nombre au nombre spécifié de décimales et ajoute un signe négatif.
Oui, la méthode numéro.tofixed () est une partie standard de JavaScript et doit être disponible dans tous les environnements JavaScript. Cependant, comme différents moteurs JavaScript gèrent les nombres différemment, les résultats peuvent ne pas être exactement les mêmes dans tous les environnements.
Si vous ne transmettez aucun argument à la méthode Number.tofixed (), il arrivera à 0 décimal par défaut. Cela signifie qu'il complètera le numéro à l'entier le plus proche.
Oui, vous pouvez utiliser la méthode numéro.tofixed () avec de grands nombres. Cependant, n'oubliez pas que JavaScript ne peut représenter avec précision que les nombres jusqu'à 2 ^ 53 - 1. Si vous essayez d'utiliser la méthode Number.tofixed () avec des nombres supérieurs à ce nombre, il peut ne pas donner de résultats précis.
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!