Je voudrais arrondir au plus 2 décimales, mais seulement si nécessaire .
Contribution:
10
1.7777777
9.1
Production:
10
1.78
9.1
Comment faire cela en JavaScript?
javascript
rounding
decimal-point
stinkycheeseman
la source
la source
Number.EPSILON
. UtilisezMath.round( num * 100 + Number.EPSILON ) / 100
.Number.EPSILON
ici?Réponses:
Utilisation
Math.round(num * 100) / 100
Edit: pour garantir que des choses comme 1,005 arrondissent correctement, nous utilisons
Math.round((num + Number.EPSILON) * 100) / 100
la source
Math.round((num + 0.00001) * 100) / 100
. EssayezMath.round((1.005 + 0.00001) * 100) / 100
etMath.round((1.0049 + 0.00001) * 100) / 100
Si la valeur est un type de texte:
Si la valeur est un nombre:
Il y a un inconvénient: des valeurs comme 1,5 donneront "1,50" en sortie. Un correctif suggéré par @minitech:
Il semble que ce
Math.round
soit une meilleure solution. Mais ce n'est pas! Dans certains cas, il ne sera PAS arrondi correctement:toFixed () ne sera PAS non plus arrondi correctement dans certains cas (testé dans Chrome v.55.0.2883.87)!
Exemples:
Je suppose que c'est parce que 1.555 est en fait quelque chose comme flotteur 1.55499994 dans les coulisses.
La solution 1 consiste à utiliser un script avec l'algorithme d'arrondi requis, par exemple:
https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
REMARQUE: ce n'est pas une solution universelle pour tout le monde. Il existe plusieurs algorithmes d'arrondi différents, votre implémentation peut être différente, dépend de vos besoins. https://en.wikipedia.org/wiki/Rounding
La solution 2 consiste à éviter les calculs frontaux et à extraire les valeurs arrondies du serveur principal.
la source
parseFloat(number.toFixed(decimalPlaces));
suit : @PerLundbergparseFloat("55.555").toFixed(2)
revient"55.55"
dans la console de développement Chrome.Vous pouvez utiliser
J'ai trouvé ça sur MDN . Leur façon d'éviter le problème avec 1.005 qui a été mentionné .
la source
+(val)
est l'équivalent coercitif de l'utilisationNumber(val)
. La concaténation de "e-2" à un nombre a entraîné une chaîne qui devait être reconvertie en nombre.roundToTwo(1.0049999999999999)
sort en 1.01 (inévitablement, depuis1.0049999999999999 == 1.005
). Il me semble que le flottant que vous obtenez si vous tapeznum = 1.005
«évidemment» «devrait» arrondir à 1,00, car la valeur exacte de num est inférieure à 1,005. Bien sûr, il me semble également que la chaîne "1.005" "évidemment" "devrait" être arrondie à 1.01. Le fait que différentes personnes semblent avoir des intuitions différentes sur le comportement correct réel ici explique en partie pourquoi c'est compliqué.1.0049999999999999
et1.005
, par définition, ils sont donc le même nombre. C'est ce qu'on appelle une coupure de dédoublement.1.00499 < 1.005
esttrue
,1.0049999999999999 < 1.005
évalue àfalse
.La réponse de MarkG est la bonne. Voici une extension générique pour un nombre quelconque de décimales.
Usage:
Test de l'unité:
la source
function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
(-1.005).round(2) === -1
Tu devrais utiliser:
Personne ne semble en être conscient
Number.EPSILON
.Il convient également de noter que ce n'est pas une bizarrerie JavaScript comme certaines personnes l'ont déclaré.
C'est simplement la façon dont les nombres à virgule flottante fonctionnent dans un ordinateur. Comme 99% des langages de programmation, JavaScript n'a pas de nombres à virgule flottante faits maison ; il s'appuie sur le CPU / FPU pour cela. Un ordinateur utilise le binaire, et en binaire, il n'y a pas de nombres comme
0.1
, mais une simple approximation binaire pour cela. Pourquoi? Pour la même raison que 1/3 ne peut pas être écrit en décimal: sa valeur est 0,33333333 ... avec une infinité de trois.Voici venir
Number.EPSILON
. Ce nombre est la différence entre 1 et le nombre suivant existant dans les nombres à virgule flottante double précision. C'est tout: il n'y a pas de nombre entre1
et 1 +Number.EPSILON
.ÉDITER:
Comme demandé dans les commentaires, clarifions une chose: ajouter
Number.EPSILON
n'est pertinent que lorsque la valeur à arrondir est le résultat d'une opération arithmétique, car elle peut avaler un delta d'erreur en virgule flottante.Ce n'est pas utile lorsque la valeur provient d'une source directe (par exemple: littéral, entrée utilisateur ou capteur).
EDIT (2019):
Comme @maganap et certains peuples l'ont souligné, il est préférable d'ajouter
Number.EPSILON
avant de multiplier:EDIT (décembre 2019):
Dernièrement, j'utilise une fonction similaire à celle-ci pour comparer les nombres compatibles avec epsilon:
Mon cas d'utilisation est une bibliothèque d'assertion + validation de données que je développe depuis de nombreuses années.
En fait, dans le code que j'utilise
ESPILON_RATE = 1 + 4 * Number.EPSILON
etEPSILON_ZERO = 4 * Number.MIN_VALUE
(quatre fois le epsilon), parce que je veux un vérificateur d'égalité suffisamment lâche pour cumuler les erreurs en virgule flottante.Jusqu'à présent, cela me semble parfait. J'espère que cela aidera.
la source
Math.round( (num + Number.EPSILON) * 100) / 100
.. Je suis d'accord également que c'est la bonne méthode pour arrondir correctement (bien que ce ne soit pas exactement ce qui a été demandé dans cette question).0.004999999999999999
le résultat d'une erreur à virgule flottante composée et le résultat mathématiquement correct était probablement 0,005. Si c'est une lecture d'un capteur? Pas tellement.Math.round(1.5)
= 2, maisMath.round(-1.5)
= -1. C'est donc parfaitement cohérent. Ici, -1 est supérieur à -2, tout comme -1000 est supérieur à -1000.01. À ne pas confondre avec de plus grands nombres absolus .On peut utiliser
.toFixed(NumberOfDecimalPlaces)
.la source
+(1.005).toFixed(2)
qui retourne1
au lieu de1.01
.Number(9).toFixed(2).replace(/0+$/, '')
=> "9."Cette question est compliquée.
Supposons que nous ayons une fonction
roundTo2DP(num)
,, qui prend un flottant comme argument et renvoie une valeur arrondie à 2 décimales. Que doit évaluer chacune de ces expressions?roundTo2DP(0.014999999999999999)
roundTo2DP(0.0150000000000000001)
roundTo2DP(0.015)
La réponse `` évidente '' est que le premier exemple devrait arrondir à 0,01 (car il est plus proche de 0,01 que de 0,02) tandis que les deux autres devraient arrondir à 0,02 (car 0,0150000000000000001 est plus proche de 0,02 que de 0,01, et parce que 0,015 est exactement à mi-chemin entre et il existe une convention mathématique selon laquelle ces nombres sont arrondis).
Le problème, que vous avez peut-être deviné, est qu'il
roundTo2DP
ne peut pas être mis en œuvre pour donner ces réponses évidentes, car les trois nombres qui lui sont transmis sont le même nombre . Les nombres à virgule flottante binaires IEEE 754 (le type utilisé par JavaScript) ne peuvent pas représenter exactement la plupart des nombres non entiers, et donc les trois littéraux numériques ci-dessus sont arrondis à un nombre à virgule flottante valide proche. Il se trouve que ce nombre est exactement0,01499999999999999944488848768742172978818416595458984375
qui est plus proche de 0,01 que de 0,02.
Vous pouvez voir que les trois nombres sont les mêmes sur la console de votre navigateur, le shell Node ou tout autre interpréteur JavaScript. Il suffit de les comparer:
Donc, quand j'écris
m = 0.0150000000000000001
, la valeur exacte de cem
que je me retrouve est plus proche0.01
qu'elle ne l'est0.02
. Et pourtant, si je me convertism
en une chaîne ...... J'obtiens 0,015, qui devrait arrondir à 0,02, et qui n'est visiblement pas le nombre à 56 décimales. J'ai dit plus tôt que tous ces nombres étaient exactement égaux. Alors, quelle magie noire est-ce?
La réponse peut être trouvée dans la spécification ECMAScript, dans la section 7.1.12.1: ToString appliquée au type Number . Ici, les règles de conversion d'un nombre m en chaîne sont définies. La partie clé est le point 5, dans lequel un entier s est généré dont les chiffres seront utilisés dans la représentation String de m :
L'élément clé ici est l'exigence que " k soit aussi petit que possible". Ce que signifie cette exigence est une exigence selon laquelle, étant donné un nombre
m
, la valeur deString(m)
doit avoir le moins de chiffres possible tout en satisfaisant à l'exigence queNumber(String(m)) === m
. Puisque nous le savons déjà0.015 === 0.0150000000000000001
, il est maintenant clair pourquoi celaString(0.0150000000000000001) === '0.015'
doit être vrai.Bien sûr, aucune de ces discussions n'a directement répondu à ce qui
roundTo2DP(m)
devrait revenir. Sim
la valeur exacte est 0,01499999999999999944488848768742172978818416595458984375, mais sa représentation de chaîne est '0,015', alors quelle est la bonne réponse - mathématiquement, pratiquement, philosophiquement, ou autre - quand nous l'arrondissons à deux décimales?Il n'y a pas de réponse correcte unique à cela. Cela dépend de votre cas d'utilisation. Vous voudrez probablement respecter la représentation String et arrondir vers le haut lorsque:
D'un autre côté, vous voulez probablement respecter la valeur à virgule flottante binaire et arrondir vers le bas lorsque votre valeur provient d'une échelle intrinsèquement continue - par exemple, s'il s'agit d'une lecture provenant d'un capteur.
Ces deux approches nécessitent un code différent. Pour respecter la représentation String du nombre, nous pouvons (avec un peu de code raisonnablement subtil) implémenter notre propre arrondi qui agit directement sur la représentation String, chiffre par chiffre, en utilisant le même algorithme que vous auriez utilisé à l'école lorsque vous ont appris à arrondir les nombres. Voici un exemple qui respecte l'exigence du PO de représenter le nombre à 2 décimales "uniquement lorsque cela est nécessaire" en supprimant les zéros de fin après la virgule; vous devrez peut-être, bien sûr, l'adapter à vos besoins précis.
Exemple d'utilisation:
La fonction ci-dessus est probablement celle que vous souhaitez utiliser pour éviter que les utilisateurs ne voient jamais les nombres qu'ils ont entrés être arrondis incorrectement.
(Comme alternative, vous pouvez également essayer la bibliothèque round10 qui fournit une fonction similaire avec une implémentation très différente.)
Mais que se passe-t-il si vous avez le deuxième type de nombre - une valeur prise sur une échelle continue, où il n'y a aucune raison de penser que les représentations décimales approximatives avec moins de décimales sont plus précises que celles avec plus? Dans ce cas, nous ne voulons pas respecter la représentation String, car cette représentation (comme expliqué dans la spécification) est déjà en quelque sorte arrondie; nous ne voulons pas faire l'erreur de dire "0,014999999 ... 375 arrondit à 0,015, ce qui arrondit à 0,02, donc 0,014999999 ... 375 arrondit à 0,02".
Ici, nous pouvons simplement utiliser la
toFixed
méthode intégrée . Notez qu'en appelantNumber()
la chaîne renvoyée partoFixed
, nous obtenons un nombre dont la représentation de chaîne n'a pas de zéros de fin (grâce à la façon dont JavaScript calcule la représentation de chaîne d'un nombre, discutée plus haut dans cette réponse).la source
roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2)
. Résultat attendu (comme PHPecho round(362.42499999999995, 2)
):362.43
. Résultat réel:362.42
round
donne 362.43. Cela semble intuitivement faux, car 362.42499999999995 est inférieur à 362.425 (en mathématiques et en code -362.42499999999995 < 362.425
c'est vrai à la fois en JS et en PHP). Depuis, la réponse de PHP ne minimise pas la distance entre les nombres à virgule flottante d'origine et arrondis362.43 - 362.42499999999995 > 362.42499999999995 - 362.42
. Selon php.net/manual/en/function.round.php , PHPround
suit la norme C99; Je vais devoir m'aventurer au pays de C pour comprendre ce qui se passe.Considérez
.toFixed()
et.toPrecision()
:http://www.javascriptkit.com/javatutors/formatnumber.shtml
la source
Une méthode d'arrondi précise. Source: Mozilla
Exemples:
la source
Math.round10(3544.5249, -2)
renvoie 3544.52 au lieu de 3544.533544.5249
2 décimales est3544.52
(erreur = 0,0049). Si c'était le cas3544.53
, l'erreur serait de 0,0051. Vous effectuez des arrondis successifs, c'est-à-dire Math.round10 (Math.round10 (3544.5249, -3), -2), ce qui donne une plus grande erreur d'arrondi et n'est donc pas souhaitable.number += 0.00011
Math.round10( Math.round10(3544.5249, -3) , -2)
Aucune des réponses trouvées ici n'est correcte . @stinkycheeseman a demandé d' arrondir , vous avez tous arrondi le nombre.
Pour arrondir, utilisez ceci:
la source
Math.ceil(1.1 * 100)/100;
- il revient1.11
, car 1.1 * 100 est110.00000000000001
conforme aux tout nouveaux navigateurs modernes Firefox, Chrome, Safari et Opera ... IE, à l'ancienne, pense toujours1.1*100=1100
.Math.ceil(num.toFixed(4) * 100) / 100
Math.ceil((1.1).toFixed(4) * 100) / 100
reviendra également1.11
dans Firefox, le problème / bug des navigateurs modernes est lié à la multiplication et les gens devraient le savoir (j'ai travaillé sur un jeu de loterie à cette époque par exemple).Voici un moyen simple de le faire:
Vous voudrez peut-être continuer et créer une fonction distincte pour le faire pour vous:
Ensuite, vous passeriez simplement la valeur.
Vous pouvez l'améliorer pour arrondir à n'importe quel nombre arbitraire de décimales en ajoutant un deuxième paramètre.
la source
la source
+(0.015).toFixed(2) == 0.01
,.Pour moi, Math.round () ne donnait pas la bonne réponse. J'ai trouvé que toFixed (2) fonctionnait mieux. Voici des exemples des deux:
la source
1.005
.(1.005).toFixed(2)
résulte toujours1.00
.Utilisez cette fonction
Number(x).toFixed(2);
la source
Number
nouveau, si vous ne voulez pas qu'il soit renvoyé sous forme de chaîne:Number(Number(x).toFixed(2));
Number
appel n'est pas nécessaire,x.toFixed(2)
fonctionne.(1).toFixed(2)
retourne1.00
, mais le questionneur est nécessaire1
dans ce cas.1.005.toFixed(2)
donne"1"
quand il devrait l'être"1.01"
.2017
Il suffit d'utiliser du code natif
.toFixed()
Si vous devez être strict et ajouter des chiffres au besoin, il peut utiliser
replace
la source
toFixed
plusieurs réponses ont été suggérées des années avant la vôtre, mais elles ne satisfont pas à la condition «uniquement si nécessaire» de la question;(1).toFixed(2)
donne"1.00"
où le demandeur a souhaité"1"
.Essayez cette solution légère :
la source
return Number(x.toFixed(digits))
?.toFixed()
n'autorise que les chiffres de toute façon.round(1.005, 2)
voir un résultat de1
au lieu de1.01
.round(0.995, 2) => 0.99
;round(1.006, 2) => 1.01
;round(1.005, 2) => 1
Il y a plusieurs façons de procéder. Pour les gens comme moi, la variante du Lodash
Usage:
Si votre projet utilise jQuery ou lodash, vous pouvez également trouver
round
méthode dans les bibliothèques.Mise à jour 1
J'ai supprimé la variante
n.toFixed(2)
, car elle n'est pas correcte. Merci @ avalanche1la source
Number.toFixed()
renverra une chaîne mais avec un symbole plus devant, l'interpréteur JS convertira la chaîne en un nombre. Ceci est un sucre de syntaxe.alert((+1234).toFixed(2))
affiche "1234.00".alert(+1234.toFixed(2))
lanceSyntaxError: identifier starts immediately after numeric literal
. Je m'en tiens à la 1ère option.362.42499999999995
. Résultat attendu (comme PHPecho round(362.42499999999995, 2)
):362.43
. Résultat réel:362.42
Si vous utilisez la bibliothèque lodash, vous pouvez utiliser la méthode ronde de lodash comme suit.
Par exemple:
la source
Depuis ES6, il existe un moyen «approprié» (sans remplacer les statiques et sans créer de solutions de contournement) de le faire en utilisant toPrecision
alors vous pouvez juste
parseFloat
et les zéros «disparaîtront».Cela ne résout pas le `` problème d'arrondi 1.005 '', car il est intrinsèque à la façon dont les fractions flottantes sont traitées .
Si vous êtes ouvert aux bibliothèques, vous pouvez utiliser bignumber.js
la source
(1.005).toPrecision(3)
retourne toujours1.00
au lieu de1.01
réellement.toPrecision
renvoie une chaîne qui modifie le type de sortie souhaité..toPrecision
méthode, c'est une spécificité des nombres à virgule flottante (quels sont les nombres en JS) - essayez1.005 - 0.005
, ça reviendra0.9999999999999999
.(1).toPrecision(3)
renvoie «1,00», mais le questionneur voulait avoir1
dans ce cas.toPrecision
fait le format, pas ce dernier, et n'est pas une réponse à la question du PO, même si cela peut sembler à première vue pertinent, il se trompe beaucoup. Voir en.wikipedia.org/wiki/Significant_figures . Par exemple,Number(123.4).toPrecision(2)
retourne"1.2e+2"
etNumber(12.345).toPrecision(2)
retourne"12"
. Je serais également d'accord avec le point de @ adamduren selon lequel il renvoie une chaîne qui n'est pas souhaitable (pas un gros problème mais pas souhaitable).MarkG et Lavamantis ont offert une bien meilleure solution que celle qui a été acceptée. C'est dommage qu'ils n'obtiennent pas plus de votes positifs!
Voici la fonction que j'utilise pour résoudre les problèmes de décimales à virgule flottante également basée sur MDN . Elle est encore plus générique (mais moins concise) que la solution de Lavamantis:
Utilisez-le avec:
Par rapport à la solution de Lavamantis, nous pouvons faire ...
la source
Cela peut vous aider:
pour plus d'informations, vous pouvez consulter ce lien
Math.round (num) vs num.toFixed (0) et incohérences du navigateur
la source
L'approche la plus simple serait d'utiliser toFixed puis de supprimer les zéros de fin à l'aide de la fonction Number:
la source
15.00
? Les nombres dans JS ne stockent pas les décimales et tout affichage tronque automatiquement les décimales en excès (tous les zéros à la fin).toFixed(2)
ici 2 est le nombre de chiffres jusqu'à ce que nous voulons arrondir ce nombre.la source
Cela peut fonctionner pour vous,
pour connaître la différence entre toFixed et round. Vous pouvez voir Math.round (num) vs num.toFixed (0) et les incohérences du navigateur .
la source
Manière la plus simple:
+num.toFixed(2)
Il le convertit en chaîne, puis de nouveau en entier / flottant.
la source
toFixed()
en 3. Il en serait ainsi+num.toFixed(3)
. Cela fonctionne comme il est censé le faire, 1,005 est arrondi à 1,00, ce qui équivaut à 1Voici une méthode prototype:
la source
Utilisez quelque chose comme ceci "parseFloat (parseFloat (value) .toFixed (2))"
la source
Une façon d'obtenir un tel arrondi uniquement si nécessaire est d'utiliser Number.prototype.toLocaleString () :
Cela fournira exactement la sortie que vous attendez, mais sous forme de chaînes. Vous pouvez toujours les reconvertir en nombres si ce n'est pas le type de données que vous attendez.
la source
toLocaleString
.Après avoir parcouru diverses itérations de toutes les manières possibles d'obtenir une précision d'arrondi décimale vraie et précise, il est clair que la solution la plus précise et la plus efficace consiste à utiliser Number.EPSILON. Cela fournit une véritable solution mathématique au problème de la précision mathématique à virgule flottante. Il peut être facilement polyfilled comme indiqué ici: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON pour prendre en charge tous les derniers utilisateurs IE restants (là encore, peut-être que nous devrait cesser de le faire).
Adapté de la solution fournie ici: https://stackoverflow.com/a/48850944/6910392
Une solution simple qui fournit un arrondi décimal, un sol et un plafond précis, avec une variable de précision en option sans ajouter une bibliothèque entière.
MISE À JOUR: Comme Sergey l'a noté dans les commentaires, il y a une limitation à cette (ou toute) méthode qui mérite d'être signalée. Dans le cas de nombres comme 0,01499999999999999999, vous rencontrerez toujours des inexactitudes qui sont le résultat de l'atteinte du bord absolu des limitations de précision pour le stockage de valeurs à virgule flottante. Il n'y a pas de solution mathématique ou autre qui peut être appliquée pour expliquer cela, car la valeur elle-même est immédiatement évaluée à 0,015. Vous pouvez le confirmer en invoquant simplement cette valeur par elle-même dans la console. En raison de cette limitation, il ne serait même pas possible d'utiliser la manipulation de chaîne pour réduire cette valeur, car sa représentation sous forme de chaîne est simplement "0,015". Toute solution pour en tenir compte devrait être appliquée logiquement à la source des données avant d'accepter la valeur dans un script,
la source
C'est la solution la plus simple et la plus élégante (et je suis le meilleur du monde;):
la source
E
notation.roundToX(362.42499999999995, 2)
. Résultat attendu (comme PHPecho round(362.42499999999995, 2)
):362.43
. Résultat réel:362.42