Question Formatage d'un nombre avec exactement deux décimales en JavaScript


J'ai cette ligne de code qui arrondit mes nombres à deux décimales. Mais je reçois des chiffres comme celui-ci: 10,8, 2,4, etc. Ce n'est pas mon idée de deux décimales, alors comment puis-je améliorer ce qui suit?

Math.round(price*Math.pow(10,2))/Math.pow(10,2);

Je veux des chiffres comme 10.80, 2.40, etc. L'utilisation de jQuery me convient parfaitement.


509
2017-11-13 01:46


origine


Réponses:


Pour formater un numéro en utilisant une notation à virgule fixe, vous pouvez simplement utiliser le toFixed méthode:

(10.8).toFixed(2); // "10.80"

var num = 2.4;
alert(num.toFixed(2)); // "2.40"

Notez que toFixed() retourne une chaîne

IMPORTANTRemarque: toFixed ne arrondit pas réellement 90% du temps, il retournera la valeur arrondie mais dans de nombreux cas, il ne fonctionne pas. Essayez ceci dans votre console:

2.005.toFixed(2)

Vous aurez la mauvaise réponse

Il n'y a aucun moyen naturel d'obtenir un arrondi décimal en javascript, vous aurez besoin de votre propre polyfill ou d'utiliser une bibliothèque. Vous pouvez regarder le polyfill de mozilla pour cela https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round


902
2017-11-13 02:02



Il s’agit d’un sujet ancien, mais les résultats Google les mieux classés et les solutions proposées partagent le même problème de décimales à virgule flottante. Voici la fonction (très générique) que j'utilise, merci à MDN:

function round(value, exp) {
  if (typeof exp === 'undefined' || +exp === 0)
    return Math.round(value);

  value = +value;
  exp = +exp;

  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));

  // Shift back
  value = value.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}

Comme nous pouvons le voir, nous n'obtenons pas ces problèmes:

round(1.275, 2);   // Returns 1.28
round(1.27499, 2); // Returns 1.27

Cette générosité fournit également des trucs sympas:

round(1234.5678, -2);   // Returns 1200
round(1.2345678e+2, 2); // Returns 123.46
round("123.45");        // Returns 123

Maintenant, pour répondre à la question du PO, il faut taper:

round(10.8034, 2).toFixed(2); // Returns "10.80"
round(10.8, 2).toFixed(2);    // Returns "10.80"

Ou, pour une fonction plus concise, moins générique:

function round2Fixed(value) {
  value = +value;

  if (isNaN(value))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + 2) : 2)));

  // Shift back
  value = value.toString().split('e');
  return (+(value[0] + 'e' + (value[1] ? (+value[1] - 2) : -2))).toFixed(2);
}

Vous pouvez l'appeler avec:

round2Fixed(10.8034); // Returns "10.80"
round2Fixed(10.8);    // Returns "10.80"

Divers exemples et tests (grâce à @ t-j-crowder!):

function round(value, exp) {
  if (typeof exp === 'undefined' || +exp === 0)
    return Math.round(value);

  value = +value;
  exp = +exp;

  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
    return NaN;

  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));

  // Shift back
  value = value.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
function naive(value, exp) {
  if (!exp) {
    return Math.round(value);
  }
  var pow = Math.pow(10, exp);
  return Math.round(value * pow) / pow;
}
function test(val, places) {
  subtest(val, places);
  val = typeof val === "string" ? "-" + val : -val;
  subtest(val, places);
}
function subtest(val, places) {
  var placesOrZero = places || 0;
  var naiveResult = naive(val, places);
  var roundResult = round(val, places);
  if (placesOrZero >= 0) {
    naiveResult = naiveResult.toFixed(placesOrZero);
    roundResult = roundResult.toFixed(placesOrZero);
  } else {
    naiveResult = naiveResult.toString();
    roundResult = roundResult.toString();
  }
  $("<tr>")
    .append($("<td>").text(JSON.stringify(val)))
    .append($("<td>").text(placesOrZero))
    .append($("<td>").text(naiveResult))
    .append($("<td>").text(roundResult))
    .appendTo("#results");
}
test(0.565, 2);
test(0.575, 2);
test(0.585, 2);
test(1.275, 2);
test(1.27499, 2);
test(1234.5678, -2);
test(1.2345678e+2, 2);
test("123.45");
test(10.8034, 2);
test(10.8, 2);
test(1.005, 2);
test(1.0005, 2);
table {
  border-collapse: collapse;
}
table, td, th {
  border: 1px solid #ddd;
}
td, th {
  padding: 4px;
}
th {
  font-weight: normal;
  font-family: sans-serif;
}
td {
  font-family: monospace;
}
<table>
  <thead>
    <tr>
      <th>Input</th>
      <th>Places</th>
      <th>Naive</th>
      <th>Thorough</th>
    </tr>
  </thead>
  <tbody id="results">
  </tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


77
2018-01-24 02:31



J'ajoute généralement ceci à ma bibliothèque personnelle, et après quelques suggestions et en utilisant la solution @TIMINeutron aussi, et la rendant adaptable pour la longueur décimale alors, celui-ci correspond le mieux:

function precise_round(num, decimals) {
   var t = Math.pow(10, decimals);   
   return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
}

fonctionnera pour les exceptions signalées.


41
2018-02-12 18:58



Je ne sais pas pourquoi je ne peux pas ajouter un commentaire à une réponse précédente (peut-être que je suis désespérément aveugle, non), mais j'ai trouvé une solution en utilisant la réponse de Miguel:

function precise_round(num,decimals) {
   return Math.round(num*Math.pow(10, decimals)) / Math.pow(10, decimals);
}

Et ses deux commentaires (de @bighostkim et @Imre):

  • Problème avec precise_round(1.275,2) ne pas retourner 1.28
  • Problème avec precise_round(6,2) ne pas retourner 6.00 (comme il voulait).

Ma dernière solution est la suivante:

function precise_round(num,decimals) {
    var sign = num >= 0 ? 1 : -1;
    return (Math.round((num*Math.pow(10,decimals)) + (sign*0.001)) / Math.pow(10,decimals)).toFixed(decimals);
}

Comme vous pouvez le voir, j'ai dû ajouter un peu de "correction" (ce n'est pas ce que c'est, mais comme Math.round est lossy - vous pouvez le vérifier sur jsfiddle.net - c'est la seule façon de savoir "réparer" " il). Il ajoute 0.001 au nombre déjà rembourré, donc il ajoute un 1 Trois 0s à droite de la valeur décimale. Donc, il devrait être sûr à utiliser.

Après cela, j'ai ajouté .toFixed(decimal) pour toujours sortir le nombre dans le format correct (avec la bonne quantité de décimales).

C'est à peu près tout. Utilisez-le bien;)

EDIT: ajout de fonctionnalités à la "correction" des nombres négatifs.


16
2018-05-01 14:18



toFixed (n) fournit n length après le point décimal; àPrécision (x)   fournit x longueur totale.

Utilisez cette méthode ci-dessous

// Example: toPrecision(4) when the number has 7 digits (3 before, 4 after)
    // It will round to the tenths place
    num = 500.2349;
    result = num.toPrecision(4); // result will equal 500.2

ET si vous voulez que le numéro soit fixe

result = num.toFixed(2);

12
2018-04-17 07:34



Une façon d'être sûr à 100% que vous obtenez un nombre avec 2 décimales:

(Math.round(num*100)/100).toFixed(2)

Si cela provoque des erreurs d'arrondi, vous pouvez utiliser ce qui suit, comme James l'a expliqué dans son commentaire:

(Math.round((num * 1000)/10)/100).toFixed(2)

12
2018-01-09 19:45



Je n'ai pas trouvé de solution précise à ce problème, j'ai donc créé le mien:

function inprecise_round(value, decPlaces) {
  return Math.round(value*Math.pow(10,decPlaces))/Math.pow(10,decPlaces);
}

function precise_round(value, decPlaces){
    var val = value * Math.pow(10, decPlaces);
    var fraction = (Math.round((val-parseInt(val))*10)/10);

    //this line is for consistency with .NET Decimal.Round behavior
    // -342.055 => -342.06
    if(fraction == -0.5) fraction = -0.6;

    val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
    return val;
}

Exemples:

function inprecise_round(value, decPlaces) {
  return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}

function precise_round(value, decPlaces) {
  var val = value * Math.pow(10, decPlaces);
  var fraction = (Math.round((val - parseInt(val)) * 10) / 10);

  //this line is for consistency with .NET Decimal.Round behavior
  // -342.055 => -342.06
  if (fraction == -0.5) fraction = -0.6;

  val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
  return val;
}

// This may produce different results depending on the browser environment
console.log("342.055.toFixed(2)         :", 342.055.toFixed(2)); // 342.06 on Chrome & IE10

console.log("inprecise_round(342.055, 2):", inprecise_round(342.055, 2)); // 342.05
console.log("precise_round(342.055, 2)  :", precise_round(342.055, 2));   // 342.06
console.log("precise_round(-342.055, 2) :", precise_round(-342.055, 2));  // -342.06

console.log("inprecise_round(0.565, 2)  :", inprecise_round(0.565, 2));   // 0.56
console.log("precise_round(0.565, 2)    :", precise_round(0.565, 2));     // 0.57


5
2018-04-29 09:38



@heridev et moi avons créé une petite fonction dans jQuery.

Vous pouvez essayer ensuite:

HTML

<input type="text" name="one" class="two-digits"><br>
<input type="text" name="two" class="two-digits">​

jQuery

// apply the two-digits behaviour to elements with 'two-digits' as their class
$( function() {
    $('.two-digits').keyup(function(){
        if($(this).val().indexOf('.')!=-1){         
            if($(this).val().split(".")[1].length > 2){                
                if( isNaN( parseFloat( this.value ) ) ) return;
                this.value = parseFloat(this.value).toFixed(2);
            }  
         }            
         return this; //for chaining
    });
});

Les DEMO EN LIGNE:

http://jsfiddle.net/c4Wqn/


3
2017-11-27 17:42