Considérons le code suivant:
for (var i=0;i<3;i++){
var num = i + 0.50;
var output = num + " " + Math.round(num) + " " + num.toFixed(0);
alert(output);
}
Dans Opera 9.63, je reçois:
0,5 1 0
1,5 2 2
2,5 3 2
En FF 3.03 je reçois:
0,5 1 1
1,5 2 2
2,5 3 3
Dans IE 7, je reçois:
0,5 1 0
1,5 2 2
2,5 3 3
Notez les résultats en gras. Pourquoi ces incohérences sont-elles présentes? Est-ce que cela signifie que toFixed(0)
devrait être évité? Quelle est la bonne façon d'arrondir un nombre au nombre entier le plus proche?
Modifier: pour répondre à votre modification, utilisez Math.round
. Vous pouvez également créer un prototype de l'objet Number
pour qu'il le fasse si vous préférez cette syntaxe.
Number.prototype.round = function() {
return Math.round(this);
}
var num = 3.5;
alert(num.round())
Je n'ai jamais utilisé Number.toFixed()
auparavant (principalement parce que la plupart des bibliothèques JS fournissent une méthode toInt()
), mais à en juger par vos résultats, il serait plus cohérent d'utiliser les méthodes Math
(round
, floor
, ceil
) puis toFixed
si vous recherchez la cohérence entre les navigateurs.
Je pense que FF fait le bon choix avec toFixed, puisque l’étape 10 ci-dessous indique "S'il y en a deux, choisissez le plus grand n".
Et comme Grant Wagner a dit: Utilisez Math.ceil (x) ou Math.floor (x) au lieu de x.toFixed ().
Tout ce qui suit est extrait de la spécification du langage ECMAScript :
15.7.4.5
Number.prototype.toFixed (fractionDigits)
Renvoie une chaîne contenant le nombre représenté par un point fixe notation avec
fractionDigits
chiffres après le point décimal. SifractionDigits
n'est pas défini,0
est supposé. Plus précisément, effectuez le Etapes suivantes:
- Soit
f
êtreToInteger(fractionDigits)
. (SifractionDigits
n'est pas défini, Cette étape produit la valeur0
).- Si
f < 0
ouf > 20
, lève une exceptionRangeError
.- Soit
x
cette valeur numérique.- Si
x
estNaN
, retournez la chaîne"NaN"
.- Soit
s
la chaîne vide.- Si
x ≥ 0
, passez à l'étape 9.- Soit s
"-"
.- Laissez
x = –x
.- Si
x ≥ 10^21
, laissezm = ToString(x)
et passez à l’étape 20.- Soit
n
un entier pour lequel la valeur mathématique exacte den ÷ 10^f – x
est aussi proche de zéro que possible. S'il y en a deux teln
, choisissez le plus grandn
.- Si
n = 0
, inséronsm
la chaîne"0"
. Sinon, laissezm
être le chaîne constituée des chiffres de la représentation décimale den
(dans l’ordre, sans zéros au début).- Si
f = 0
, passez à l'étape 20.- Soit
k
le nombre de caractères dem
.- Si
k > f
, passez à l'étape 18.- Soit
z
la chaîne constituée par les occurrencesf+1–k
du caractère'0'
.- Soit
m
la concaténation de chaînesz
etm
.- Laissez
k = f + 1
.- Soit
a
les premiersk–f
caractères dem
, etb
, lef
caractères restants dem
.- Soit
m
la concaténation des trois chaînesa
,"."
etb
.- Renvoie la concaténation des chaînes
s
etm
.La propriété
length
de la méthodetoFixed
est1
.Si la méthode
toFixed
est appelée avec plusieurs arguments, alors le le comportement n'est pas défini (voir section 15).Une implémentation est autorisée à étendre le comportement de
toFixed
pour les valeurs defractionDigits
inférieures à0
ou supérieures à20
. Dans ce castoFixed
ne jetterait pas nécessairementRangeError
pour de telles valeurs.NOTE La sortie de
toFixed
peut être plus précise quetoString
pour certaines valeurs parce quetoString
n’imprime que suffisamment de chiffres significatifs pour distinguer le nombre des valeurs numériques adjacentes. Par exemple,(1000000000000000128).toString()
renvoie"1000000000000000100"
, alors que(1000000000000000128).toFixed(0)
renvoie"1000000000000000128"
.
Pour répondre à vos deux d'origine questions/questions:
Le problème ici réside dans l'idée fausse que ceux-ci devraient toujours donner le même résultat. En fait, ils sont régis par des règles différentes. Regardez les nombres négatifs, par exemple. Parce que Math.round
utilise "arrondir la moitié" comme règle, vous verrez que Math.round(-1.5)
est évalué à -1
même si Math.round(1.5)
est évalué à 2
.
Number.prototype.toFixed
, d'autre part, utilise ce qui est fondamentalement équivalent à "arrondir la moitié de zéro" comme règle, selon l'étape 6 de la spécification , qui dit essentiellement de traiter les négatifs comme des nombres positifs, puis rajoutez le signe négatif à la fin. Ainsi, (-1.5).toFixed(0) === "-2"
et (1.5).toFixed(0) === "2"
sont des instructions vraies dans tous les navigateurs conformes aux spécifications. Notez que ces valeurs sont des chaînes, pas des nombres. Notez en outre que -1.5.toFixed(0)
et -(1.5).toFixed(0)
sont tous deux === -2
(le nombre) en raison de la priorité de l'opérateur.
La plupart des navigateurs modernesou du moins ceux que vous pourriez être amené à supporter au moment d'écrire ces lignes à l'exception de IE - doit implémenter correctement les spécifications. (Selon le commentaire de Renee , le problème toFixed
que vous avez signalé dans Opera a été corrigé, vraisemblablement depuis qu’ils ont commencé à utiliser le même moteur JS que Chrome.) Il convient de rappeler que même si les spécifications ont été mises en œuvre de manière cohérente dans tous les cas. navigateurs, le comportement défini dans la spécification, en particulier pour les arrondis toFixed
, peut encore sembler peu intuitif pour les développeurs JS "simples mortels" qui attendent une vraie précision mathématique - voir Javascript toFixed Not Rounding et cela "fonctionne comme prévu "bug qui a été archivé sur le moteur V8 JS pour des exemples.
En bref, il s’agit de deux fonctions différentes avec deux types de retour différents et deux ensembles de règles différents pour l’arrondi.
Comme d'autres l'ont suggéré, je voudrais également dire "utilisez la fonction qui convient à votre cas d'utilisation particulier" (en prenant un soin particulier à noter les particularités de toFixed
, en particulier la mise en œuvre errante d'IE). Personnellement, je serais plutôt enclin à recommander une combinaison explicite de Edit: ... cependant, après avoir lu votre clarification, votre cas d'utilisation (arrondi à un nombre entier) appelle définitivement la fonction bien nommée Math.round/ceil/floor
, encore une fois, comme d'autres l'ont mentionné.Math.round
.
toFixed () renvoie une valeur de chaîne. De Javascript: Le guide définitif
Convertit un nombre en chaîne contenant un nombre spécifié de chiffres après la décimale.
Math.round () retourne un entier.
De toute évidence, toFixed () semble être plus utile pour l'argent, par exemple,
'$' + 12.34253.toFixed (2) = '12,34 $'
Il semble vraiment dommage que toFixed () ne semble pas arrondir correctement!
Au lieu de toFixed(0)
, utilisez Math.ceil()
ou Math.floor()
, selon les besoins.
Cela semble définitivement le cas, si vous obtenez des réponses incohérentes.
Je peux seulement deviner que votre intention avec toinfixed (0) est de transformer un nombre décimal en entier, auquel cas je recommande Math.floor (). Il y a un peu plus de discussion sur la meilleure façon de le faire dans cette question .