Pregunta Formatear un número con exactamente dos decimales en JavaScript


Tengo esta línea de código que redondea mis números a dos decimales. Pero obtengo números como este: 10.8, 2.4, etc. Estos no son mi idea de dos decimales, entonces ¿cómo puedo mejorar lo siguiente?

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

Quiero números como 10.80, 2.40, etc. El uso de jQuery está bien para mí.


509
2017-11-13 01:46


origen


Respuestas:


Para formatear un número usando notación de punto fijo, simplemente puede usar ajustado método:

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

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

Tenga en cuenta que toFixed() devuelve una cadena.

IMPORTANTE: Tenga en cuenta que toFixed no se redondea, el 90% de las veces devolverá el valor redondeado pero, en muchos casos, no funciona. Prueba esto en tu consola:

2.005.toFixed(2)

Obtendrás la respuesta incorrecta

No existe una forma natural de obtener un redondeo decimal en JavaScript, necesitará su propio relleno o usar una biblioteca. Puedes mirar el polyfill de mozilla para esto https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round


902
2017-11-13 02:02



Este es un tema antiguo, pero los resultados de Google mejor clasificados y las soluciones ofrecidas comparten el mismo problema de decimales en coma flotante. Aquí está la función (muy genérica) que uso, gracias a 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));
}

Como podemos ver, no obtenemos estos problemas:

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

Esta genericidad también proporciona algunas cosas interesantes:

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

Ahora, para responder la pregunta del OP, uno tiene que escribir:

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

O, para una función más concisa, menos genérica:

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);
}

Puedes llamarlo con:

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

Varios ejemplos y pruebas (gracias a @ 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



Por lo general, agrego esto a mi biblioteca personal, y después de algunas sugerencias y el uso de la solución @TIMINeutron también, y por lo que es adaptable para la longitud decimal, este se ajusta mejor:

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);
}

funcionará para las excepciones informadas.


41
2018-02-12 18:58



No sé por qué no puedo agregar un comentario a una respuesta anterior (tal vez estoy irremediablemente ciego, no sé), pero se me ocurrió una solución usando la respuesta de @Miguel:

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

Y sus dos comentarios (de @bighostkim y @Imre):

  • Problema con precise_round(1.275,2) no regresando 1.28
  • Problema con precise_round(6,2) no regresaba 6.00 (como él quería).

Mi solución final es la siguiente:

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);
}

Como puede ver, tuve que agregar un poco de "corrección" (no es lo que es, pero como Math.round tiene pérdidas, puede verificarlo en jsfiddle.net, esta es la única forma que sabía de "corregir" " eso). Agrega 0.001 al número ya acolchado, por lo que agrega un 1 Tres 0s a la derecha del valor decimal. Por lo tanto, debe ser seguro de usar.

Después de eso agregué .toFixed(decimal) para siempre dar salida al número en el formato correcto (con la cantidad correcta de decimales).

Así que eso es más o menos. Úsalo bien ;)

EDITAR: funcionalidad añadida a la "corrección" de números negativos.


16
2018-05-01 14:18



toFixed (n) proporciona n longitud después del punto decimal; toPrecision (x)   proporciona x longitud total.

Use este método a continuación

// 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

Y si desea que el número se fije, use

result = num.toFixed(2);

12
2018-04-17 07:34



Una forma de estar 100% seguro de que obtienes un número con 2 decimales:

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

Si esto causa errores de redondeo, puede usar lo siguiente como James ha explicado en su comentario:

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

12
2018-01-09 19:45



No encontré una solución precisa para este problema, así que creé la mía:

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;
}

Ejemplos:

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 y yo creamos una pequeña función en jQuery.

Puedes intentarlo a continuación:

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
    });
});

1. DEMO EN LÍNEA:

http://jsfiddle.net/c4Wqn/


3
2017-11-27 17:42