¿Cómo formatear un flotante en javascript?

427

En JavaScript, al convertir de un flotante a una cadena, ¿cómo puedo obtener solo 2 dígitos después del punto decimal? Por ejemplo, 0,34 en lugar de 0,3445434.

jww
fuente
16
Solo un poco de selección: ¿desea 'cortar' todos menos los dos primeros dígitos, o desea redondear a dos dígitos?
xtofl

Respuestas:

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

Los detalles , en caso de que el código no se explique por sí mismo.

editar: ... o simplemente usar toFixed, según lo propuesto por Tim Büthe . Olvidé esa, gracias (y un voto positivo) por el recordatorio :)

kkyy
fuente
1
Estaba usando esto en la biblioteca "Highchart", donde no acepta valores de cadena, por lo tanto toFixed no funcionó para mí, Math.round resolvió mi problema, gracias
Swapnil Chincholkar
44
toFixed()imitará lo que hace algo así printf()en C. Sin embargo, toFixed()y Math.round()manejará el redondeo de manera diferente. En este caso, toFixed()tendrá el mismo tipo de efecto Math.floor()que tendría (siempre que multiplique el original por 10 ^ n de antemano y llame toFixed()con n dígitos). La "exactitud" de la respuesta depende mucho de lo que el OP quiere aquí, y ambos son "correctos" a su manera.
DDPWNAGE
838

Hay funciones para redondear números. Por ejemplo:

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

imprimirá 5.04.

EDITAR: violín

Tim Büthe
fuente
77
Sin embargo, recomendaría no usar print () en un navegador
cobbal
70
Tenga cuidado con esto, toFixed () devuelve una cadena: var x = 5.036432346; var y = x.toFixed(2) + 100; yserá igual"5.03100"
Vlad
55
Tenga en cuenta que (1e100) .toFixed (2) === "1e + 100"
qbolec
77
Además, tenga cuidado con el redondeo inconsistente: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)...
Skippy le Grand Gourou
3
Si busca un equivalente de toFixed pero con redondeo consistente, use toLocaleString: (0.345) .toLocaleString ('en-EN', {minimumFractionDigits: 2, maximumFractionDigits: 2})
fred727
185

Tenga cuidado al usar toFixed():

Primero, el redondeo del número se realiza utilizando la representación binaria del número, lo que puede conducir a un comportamiento inesperado. Por ejemplo

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

en lugar de '0.6'.

En segundo lugar, hay un error de IE con toFixed(). En IE (al menos hasta la versión 7, no comprobé IE8), lo siguiente es cierto:

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

Puede ser una buena idea seguir la sugerencia de kkyy o utilizar una toFixed()función personalizada , p. Ej.

function toFixed(value, precision) {
    var power = Math.pow(10, precision || 0);
    return String(Math.round(value * power) / power);
}
Christoph
fuente
Sí, esto puede ser muy importante al crear código para predecir precios. ¡Gracias! +1
Fabio Milheiro
10
Sugeriría agregar el .toFixed()método nativo en el valor de retorno, que agregará la cantidad requerida de precisión, por ejemplo: return (Math.round(value * power) / power).toFixed(precision);y también devolverá el valor como una cadena. De lo contrario, se ignora la precisión de 20 para decimales más pequeños
William Joss Crowcroft
3
Una nota con respecto a toFixed: tenga en cuenta que aumentar la precisión puede producir resultados inesperados:, (1.2).toFixed(16) === "1.2000000000000000"mientras que (1.2).toFixed(17) === "1.19999999999999996"(en Firefox / Chrome; en IE8, este último no se cumple debido a la menor precisión que IE8 puede ofrecer internamente).
jakub.g
2
Tenga en cuenta que incluso (0.598).toFixed(2)no produce 0.6. Produce 0.60:)
qbolec
1
Además, tenga cuidado de redondeo inconstistent: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2).
Skippy le Grand Gourou
36

Un problema más a tener en cuenta es que toFixed()puede producir ceros innecesarios al final del número. Por ejemplo:

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

La idea es limpiar la salida usando RegExp:

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

El RegExpcoincida con los ceros a la derecha (y opcionalmente la coma decimal) para asegurarse de que se ve bien para los enteros también.

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
fuente
Number.prototype.minFixed = function (decimales) {return this.toFixed (decimales) .replace (/ \.? 0 * $ /, ""); }
Luc Bloom
Esto debería aceptarse, los ceros finales son molestos, estaba buscando exactamente esta solución, gj.
exoslav
1
Los ceros finales pueden ser molestos, pero esto es exactamente lo que el nombre del método "toFixed" promete hacer;)
ksadowski
11
var x = 0.3445434
x = Math.round (x*100) / 100 // this will make nice rounding
Ilya Birman
fuente
Math.round (1.015 * 100) / 100 da 1.01 mientras que esperaríamos que sea 1.02?
gaurav5430
6

Hay un problema con todas esas soluciones flotando usando multiplicadores. Desafortunadamente, las soluciones de kkyy y Christoph están equivocadas.

Pruebe su código para el número 551.175 con 2 decimales: ¡se redondeará a 551.17 mientras que debería ser 551.18 ! Pero si pruebas para ex. 451.175 estará bien - 451.18. Por lo tanto, es difícil detectar este error a primera vista.

El problema es con la multiplicación: intente 551.175 * 100 = 55117.49999999999 (¡ups!)

Entonces, mi idea es tratarlo con toFixed () antes de usar Math.round ();

function roundFix(number, precision)
{
    var multi = Math.pow(10, precision);
    return Math.round( (number * multi).toFixed(precision + 1) ) / multi;
}
ArteQ
fuente
1
Ese es el problema con la aritmética en js: (551.175 * 10 * 10)! == (551.175 * 100). Debe usar incrementos decimales para mover la coma para resultados decimales no reales.
Kir Kanos
+1 por notar esto, sin embargo, también toFixedse ve afectado: (0.335).toFixed(2) == 0.34 == (0.345).toFixed(2)... Cualquiera que sea el método utilizado, es mejor agregar un épsilon antes del redondeo.
Skippy le Grand Gourou
5

La clave aquí, supongo, es redondear correctamente primero, luego puede convertirlo a String.

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

Ahora puede formatear este valor de forma segura con toFixed (p). Entonces, con su caso específico:

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

Si desea la cadena sin redondeo, puede usar este RegEx (tal vez no sea la forma más eficiente ... pero es realmente fácil)

(2.34567778).toString().match(/\d+\.\d{2}/)[0]
// '2.34'
Pablo Andres Diaz Mazzaro
fuente
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
fuente
gran respuesta, excepto que le faltan puntos y comas (No, en es6 los puntos y comas no son obsoletos y todavía tenemos que usarlos en algunos casos). Tenía que también editar última fila a: return float_part ? int_part+'.'+float_part : int_part;de lo contrario si usted pasó entero, se volvió número con un punto al final (Ejemplo de entrada 2100, salida: 2100.)
Kuba SIMONOVSKY
0

¿Quizás también quieras un separador decimal? Aquí hay una función que acabo de hacer:

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
fuente
0

No hay forma de evitar el redondeo inconsistente para precios con x.xx5 como valor real usando multiplicación o división. Si necesita calcular los precios correctos del lado del cliente, debe mantener todas las cantidades en centavos. Esto se debe a la naturaleza de la representación interna de los valores numéricos en JavaScript. Tenga en cuenta que Excel tiene los mismos problemas, por lo que la mayoría de las personas no notarían los pequeños errores causados ​​por este fenómeno. Sin embargo, los errores pueden acumularse cada vez que sumas muchos valores calculados, hay una teoría completa que involucra el orden de los cálculos y otros métodos para minimizar el error en el resultado final. Para enfatizar los problemas con los valores decimales, tenga en cuenta que 0.1 + 0.2 no es exactamente igual a 0.3 en JavaScript, mientras que 1 + 2 es igual a 3.

Dony
fuente
la solución sería separar la parte completa y la parte decimal, y representarlas como enteros en la base 10, en lugar de usar flotantes, aquí funciona sin problemas para prettyPrint, pero en general debe elegir entre una base y otra, una representación para números reales y otro, cada uno tiene sus problemas
reúne el
"Excel sufre los mismos problemas". fuente ?
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"
se reúne
fuente
0

Yo uso este código para formatear flotadores. Se basa en toPrecision()pero elimina los ceros innecesarios. Agradecería sugerencias sobre cómo simplificar la expresión regular.

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

Ejemplo de uso:

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>');
marca
fuente