Comment formater un float en javascript?

427

En JavaScript, lors de la conversion d'un flottant en une chaîne, comment puis-je obtenir seulement 2 chiffres après la virgule décimale? Par exemple, 0,34 au lieu de 0,3445434.

jww
la source
16
Juste un peu de choix: voulez-vous "couper" tous sauf les deux premiers chiffres, ou voulez-vous arrondir à deux chiffres?
xtofl

Réponses:

232
var result = Math.round(original*100)/100;

Les détails , au cas où le code ne serait pas explicite.

modifier: ... ou tout simplement utiliser toFixed, comme proposé par Tim Büthe . Oublié celui-là, merci (et un vote positif) pour rappel :)

kkyy
la source
1
J'utilisais cela dans la bibliothèque "Highchart" où il n'accepte pas les valeurs de chaîne, donc toFixed n'a pas fonctionné pour moi, Math.round a résolu mon problème, merci
Swapnil Chincholkar
4
toFixed()imitera ce que fait quelque chose printf()en C. Cependant, toFixed()et Math.round()gérera l'arrondi différemment. Dans ce cas, toFixed()aura le même type d'effet Math.floor()(à condition de multiplier l'original par 10 ^ n au préalable et d'appeler toFixed()avec n chiffres). La «justesse» de la réponse dépend beaucoup de ce que le PO souhaite ici, et les deux sont «correctes» à leur manière.
DDPWNAGE
838

Il existe des fonctions pour arrondir les nombres. Par exemple:

var x = 5.0364342423;
print(x.toFixed(2));

imprimera 5.04.

EDIT: Fiddle

Tim Büthe
la source
7
Je recommanderais cependant de ne pas utiliser print () dans un navigateur
cobbal
70
Soyez prudent à ce sujet, toFixed () renvoie une chaîne: var x = 5.036432346; var y = x.toFixed(2) + 100; ysera égale"5.03100"
Vlad
5
Sachez que (1e100) .toFixed (2) === "1e + 100"
qbolec
7
Attention aussi aux arrondis incohérents: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)
Skippy le Grand Gourou
3
Si vous recherchez un équivalent de toFixed mais avec un arrondi cohérent, utilisez toLocaleString: (0.345) .toLocaleString ('en-EN', {minimumFractionDigits: 2, maximumFractionDigits: 2})
fred727
185

Soyez prudent lorsque vous utilisez toFixed():

Tout d'abord, l'arrondi du nombre est effectué à l'aide de la représentation binaire du nombre, ce qui peut entraîner un comportement inattendu. Par exemple

(0.595).toFixed(2) === '0.59'

au lieu de '0.6'.

Deuxièmement, il y a un bogue IE avec toFixed(). Dans IE (au moins jusqu'à la version 7, n'a pas vérifié IE8), ce qui suit est vrai:

(0.9).toFixed(0) === '0'

Il peut être judicieux de suivre la suggestion de kkyy ou d'utiliser une toFixed()fonction personnalisée , par exemple

function toFixed(value, precision) {
    var power = Math.pow(10, precision || 0);
    return String(Math.round(value * power) / power);
}
Christoph
la source
Oui, cela peut être très important lors de la création de code pour prédire les prix. Merci! +1
Fabio Milheiro
10
Je suggère d'ajouter la .toFixed()méthode native dans la valeur de retour, ce qui ajoutera la précision requise, par exemple: return (Math.round(value * power) / power).toFixed(precision);et renverra également la valeur sous forme de chaîne. Sinon, la précision de 20 est ignorée pour les décimales plus petites
William Joss Crowcroft
3
Une remarque concernant toFixed: notez que l'augmentation de la précision peut donner des résultats inattendus:, (1.2).toFixed(16) === "1.2000000000000000"tandis que (1.2).toFixed(17) === "1.19999999999999996"(dans Firefox / Chrome; dans IE8, ce dernier ne tient pas en raison de la précision inférieure qu'IE8 peut offrir en interne).
jakub.g
2
Veuillez noter que même (0.598).toFixed(2)ne produit pas 0.6. Il produit 0.60:)
qbolec
1
De plus, méfiez - vous de l' arrondissement inconstistent: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2).
Skippy le Grand Gourou
36

Un autre problème à prendre en compte est qu'il toFixed()peut produire des zéros inutiles à la fin du nombre. Par exemple:

var x=(23-7.37)
x
15.629999999999999
x.toFixed(6)
"15.630000"

L'idée est de nettoyer la sortie en utilisant RegExp:

function humanize(x){
  return x.toFixed(6).replace(/\.?0*$/,'');
}

Le RegExpcorrespond aux zéros de fin (et éventuellement le point décimal) pour s'assurer qu'il semble également bon pour les entiers.

humanize(23-7.37)
"15.63"
humanize(1200)
"1200"
humanize(1200.03)
"1200.03"
humanize(3/4)
"0.75"
humanize(4/3)
"1.333333"
qbolec
la source
Number.prototype.minFixed = fonction (décimales) {renvoie this.toFixed (décimales) .replace (/ \.? 0 * $ /, ""); }
Luc Bloom
Cela devrait être accepté, les zéros de fin sont ennuyeux, je cherchais exactement cette solution, gj.
exoslav
1
La fin des zéros peut être agaçante, mais c'est exactement ce que le nom de la méthode "toFixed" promet de faire;)
ksadowski
11
var x = 0.3445434
x = Math.round (x*100) / 100 // this will make nice rounding
Ilya Birman
la source
Math.round (1.015 * 100) / 100 donne 1.01 alors que nous nous attendrions à ce que ce soit 1.02?
gaurav5430
6

Il y a un problème avec toutes ces solutions flottant à l'aide de multiplicateurs. Malheureusement, les solutions de Kkyy et de Christoph sont fausses.

Veuillez tester votre code pour le numéro 551.175 avec 2 décimales - il arrondira à 551.17 alors qu'il devrait être 551.18 ! Mais si vous testez par ex. 451.175 ce sera ok - 451.18. Il est donc difficile de repérer cette erreur à première vue.

Le problème est avec la multiplication: essayez 551.175 * 100 = 55117.49999999999 (ups!)

Donc mon idée est de le traiter avec toFixed () avant d'utiliser Math.round ();

function roundFix(number, precision)
{
    var multi = Math.pow(10, precision);
    return Math.round( (number * multi).toFixed(precision + 1) ) / multi;
}
ArteQ
la source
1
C'est le problème avec l'arithmétique en js: (551.175 * 10 * 10)! == (551.175 * 100). Vous devez utiliser des incréments décimaux pour déplacer la virgule pour des résultats décimaux non réels.
Kir Kanos
+1 pour le remarquer, mais toFixedest également affecté - (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)… Quelle que soit la méthode utilisée, il vaut mieux ajouter un epsilon avant l'arrondi.
Skippy le Grand Gourou
5

La clé ici, je suppose, consiste à arrondir correctement d'abord, puis vous pouvez le convertir en chaîne.

function roundOf(n, p) {
    const n1 = n * Math.pow(10, p + 1);
    const n2 = Math.floor(n1 / 10);
    if (n1 >= (n2 * 10 + 5)) {
        return (n2 + 1) / Math.pow(10, p);
    }
    return n2 / Math.pow(10, p);
}

// All edge cases listed in this thread
roundOf(95.345, 2); // 95.35
roundOf(95.344, 2); // 95.34
roundOf(5.0364342423, 2); // 5.04
roundOf(0.595, 2); // 0.60
roundOf(0.335, 2); // 0.34
roundOf(0.345, 2); // 0.35
roundOf(551.175, 2); // 551.18
roundOf(0.3445434, 2); // 0.34

Vous pouvez maintenant formater cette valeur en toute sécurité avec toFixed (p). Donc, avec votre cas spécifique:

roundOf(0.3445434, 2).toFixed(2); // 0.34
Steven
la source
3

Si vous voulez la chaîne sans rond, vous pouvez utiliser ce RegEx (ce n'est peut-être pas le moyen le plus efficace ... mais c'est vraiment facile)

(2.34567778).toString().match(/\d+\.\d{2}/)[0]
// '2.34'
Pablo Andres Diaz Mazzaro
la source
1
function trimNumber(num, len) {
  const modulu_one = 1;
  const start_numbers_float=2;
  var int_part = Math.trunc(num);
  var float_part = String(num % modulu_one);
      float_part = float_part.slice(start_numbers_float, start_numbers_float+len);
  return int_part+'.'+float_part;
}
ofir_aghai
la source
bonne réponse sauf qu'il vous manque des points-virgules (Non, dans es6 les points-virgules ne sont pas obsolètes et nous devons encore les utiliser dans certains cas). Je devais aussi modifier la dernière ligne à: return float_part ? int_part+'.'+float_part : int_part;sinon , si vous avez passé entier, il est revenu avec un nombre de points à la fin (entrée exemple: 2100, sortie: 2100.)
Kuba Šimonovský
0

Peut-être voudrez-vous également un séparateur décimal? Voici une fonction que je viens de faire:

function formatFloat(num,casasDec,sepDecimal,sepMilhar) {
    if (num < 0)
    {
        num = -num;
        sinal = -1;
    } else
        sinal = 1;
    var resposta = "";
    var part = "";
    if (num != Math.floor(num)) // decimal values present
    {
        part = Math.round((num-Math.floor(num))*Math.pow(10,casasDec)).toString(); // transforms decimal part into integer (rounded)
        while (part.length < casasDec)
            part = '0'+part;
        if (casasDec > 0)
        {
            resposta = sepDecimal+part;
            num = Math.floor(num);
        } else
            num = Math.round(num);
    } // end of decimal part
    while (num > 0) // integer part
    {
        part = (num - Math.floor(num/1000)*1000).toString(); // part = three less significant digits
        num = Math.floor(num/1000);
        if (num > 0)
            while (part.length < 3) // 123.023.123  if sepMilhar = '.'
                part = '0'+part; // 023
        resposta = part+resposta;
        if (num > 0)
            resposta = sepMilhar+resposta;
    }
    if (sinal < 0)
        resposta = '-'+resposta;
    return resposta;
}
Rodrigo
la source
0

Il n'y a aucun moyen d'éviter l'arrondissement incohérent des prix avec x.xx5 comme valeur réelle en utilisant soit la multiplication soit la division. Si vous devez calculer les prix corrects côté client, vous devez conserver tous les montants en cents. Cela est dû à la nature de la représentation interne des valeurs numériques en JavaScript. Notez qu'Excel souffre des mêmes problèmes afin que la plupart des gens ne remarquent pas les petites erreurs causées par ce phénomène. Cependant, des erreurs peuvent s'accumuler chaque fois que vous additionnez un grand nombre de valeurs calculées, il existe toute une théorie à ce sujet impliquant l'ordre des calculs et d'autres méthodes pour minimiser l'erreur dans le résultat final. Pour souligner les problèmes avec les valeurs décimales, veuillez noter que 0,1 + 0,2 n'est pas exactement égal à 0,3 en JavaScript, tandis que 1 + 2 est égal à 3.

Dony
la source
la solution serait de séparer la partie entière et la partie décimale, et de les représenter sous forme d'entiers dans la base 10, au lieu d'utiliser des flottants, ici cela fonctionne sans problème pour prettyPrint, mais en général vous devez choisir entre une base et une autre, une représentation pour des nombres réels et un autre, chacun a ses problèmes
reuns
"Excel souffre des mêmes problèmes". la source ?
gaurav5430
0
/** don't spend 5 minutes, use my code **/
function prettyFloat(x,nbDec) { 
    if (!nbDec) nbDec = 100;
    var a = Math.abs(x);
    var e = Math.floor(a);
    var d = Math.round((a-e)*nbDec); if (d == nbDec) { d=0; e++; }
    var signStr = (x<0) ? "-" : " ";
    var decStr = d.toString(); var tmp = 10; while(tmp<nbDec && d*tmp < nbDec) {decStr = "0"+decStr; tmp*=10;}
    var eStr = e.toString();
    return signStr+eStr+"."+decStr;
}

prettyFloat(0);      //  "0.00"
prettyFloat(-1);     // "-1.00"
prettyFloat(-0.999); // "-1.00"
prettyFloat(0.5);    //  "0.50"
reuns
la source
0

J'utilise ce code pour formater les flottants. Il est basé sur toPrecision()mais il supprime les zéros inutiles. Je serais heureux de recevoir des suggestions sur la façon de simplifier l'expression rationnelle.

function round(x, n) {
    var exp = Math.pow(10, n);
    return Math.floor(x*exp + 0.5)/exp;
}

Exemple d'utilisation:

function test(x, n, d) {
    var rounded = rnd(x, d);
    var result = rounded.toPrecision(n);
    result = result.replace(/\.?0*$/, '');
    result = result.replace(/\.?0*e/, 'e');
    result = result.replace('e+', 'e');
    return result;  
}

document.write(test(1.2000e45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2000e+45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2340e45, 3, 2) + '=' + '1.23e45' + '<br>');
document.write(test(1.2350e45, 3, 2) + '=' + '1.24e45' + '<br>');
document.write(test(1.0000, 3, 2) + '=' + '1' + '<br>');
document.write(test(1.0100, 3, 2) + '=' + '1.01' + '<br>');
document.write(test(1.2340, 4, 2) + '=' + '1.23' + '<br>');
document.write(test(1.2350, 4, 2) + '=' + '1.24' + '<br>');
marque
la source