truncar round remove redondear hacia decimals decimales arriba javascript decimal rounding decimal-point

remove - round up javascript



Redondear a un máximo de 2 decimales(solo si es necesario) (30)

Me gustaría redondear como máximo 2 decimales, pero solo si es necesario .

Entrada:

10 1.7777777 9.1

Salida:

10 1.78 9.1

¿Cómo puedo hacer esto en JavaScript ?


2017
Solo usa el código nativo .toFixed()

number = 1.2345; number.toFixed(2) // "1.23"

Si necesita ser estricto y agregar dígitos solo si es necesario, puede usar replace

number = 1; // "1" number.toFixed(5).replace(//.?0*$/g,'''');


Aquí hay una manera simple de hacerlo:

Math.round(value * 100) / 100

Es posible que desee seguir adelante y hacer una función separada para hacerlo por usted aunque:

function roundToTwo(value) { return(Math.round(value * 100) / 100); }

Entonces simplemente pasarías el valor.

Podría mejorarlo para redondearlo a cualquier número arbitrario de decimales agregando un segundo parámetro.

function myRound(value, places) { var multiplier = Math.pow(10, places); return (Math.round(value * multiplier) / multiplier); }



Deberías usar:

Math.round( num * 100 + Number.EPSILON ) / 100

Nadie parece ser consciente de Number.EPSILON .

También vale la pena señalar que esto no es una rareza de JavaScript como algunas personas dijeron.

Esa es simplemente la forma en que los números de punto flotante funcionan en una computadora. Como el 99% de los lenguajes de programación, JavaScript no tiene números de punto flotante hechos en casa ; se basa en la CPU / FPU para eso. Una computadora usa binario, y en binario, no hay ningún número como 0.1 , sino una mera aproximación binaria para eso. ¿Por qué? Por la misma razón que 1/3 no se puede escribir en decimal: su valor es 0.33333333 ... con una infinidad de tres.

Aquí viene Number.EPSILON . Ese número es la diferencia entre 1 y el siguiente número existente en los números de punto flotante de doble precisión. Eso es todo: no hay un número entre 1 y 1 + Number.EPSILON .

EDITAR:

Como se pidió en los comentarios, aclaremos una cosa: agregar Number.EPSILON es relevante solo cuando el valor a redondear es el resultado de una operación aritmética, ya que puede tragar un delta de error de punto flotante.

No es útil cuando el valor proviene de una fuente directa (por ejemplo: literal, entrada de usuario o sensor).


Esta pregunta es complicada.

Supongamos que tenemos una función, roundTo2DP(num) , que toma un flotante como argumento y devuelve un valor redondeado a 2 decimales. ¿Qué debe evaluar cada una de estas expresiones?

  • roundTo2DP(0.014999999999999999)
  • roundTo2DP(0.0150000000000000001)
  • roundTo2DP(0.015)

La respuesta ''obvia'' es que el primer ejemplo debería redondear a 0.01 (porque está más cerca de 0.01 que a 0.02) mientras que los otros dos deben redondear a 0.02 (porque 0.0150000000000000001 está más cerca de 0.02 que a 0.01, y porque 0.015 está exactamente a mitad de camino ellos y hay una convención matemática de que tales números se redondean).

El problema, que puede haber adivinado, es que roundTo2DP no puede implementarse para dar esas respuestas obvias, porque los tres números que se le pasan son el mismo . Los números binarios de punto flotante IEEE 754 (el tipo utilizado por JavaScript) no pueden representar exactamente la mayoría de los números no enteros, por lo que los tres literales numéricos anteriores se redondean a un número de punto flotante válido cercano. Este número, como sucede, es exactamente

0.01499999999999999944488848768742172978818416595458984375

que está más cerca de 0.01 que de 0.02.

Puede ver que los tres números son los mismos en la consola de su navegador, el shell Node u otro intérprete de JavaScript. Solo compáralos:

> 0.014999999999999999 === 0.0150000000000000001 true

Entonces, cuando escribo m = 0.0150000000000000001 , el valor exacto de m que termino es más cercano a 0.01 que a 0.02 . Y sin embargo, si convierto m a un String ...

> var m = 0.0150000000000000001; > console.log(String(m)); 0.015 > var m = 0.014999999999999999; > console.log(String(m)); 0.015

... Obtengo 0.015, que debería redondear a 0.02, y que es notablemente no el número de 56 decimales al que dije antes que todos estos números eran exactamente iguales a. Entonces, ¿qué magia oscura es esto?

La respuesta se puede encontrar en la especificación ECMAScript, en la sección 7.1.12.1: ToString aplicado al tipo de Número . Aquí se establecen las reglas para convertir algún número m en una cadena. La parte clave es el punto 5, en el que se genera un entero s cuyos dígitos se utilizarán en la representación de cadena de m :

sea n , k , y s sean enteros tales que k ≥ 1, 10 k -1s <10 k , el valor del Número para s × 10 n - k es m , yk es lo más pequeño posible. Tenga en cuenta que k es el número de dígitos en la representación decimal de s , que s no es divisible por 10, y que el dígito menos significativo de s no está necesariamente determinado de forma única por estos criterios.

La parte clave aquí es el requisito de que " k es lo más pequeño posible". Lo que ese requisito equivale a es un requisito que, dado un Número m , el valor de la String(m) debe tener el menor número posible de dígitos mientras sigue satisfaciendo el requisito de que el Number(String(m)) === m . Como ya sabemos que 0.015 === 0.0150000000000000001 , ahora está claro por qué String(0.0150000000000000001) === ''0.015'' debe ser verdadero.

Por supuesto, ninguna de estas discusiones ha respondido directamente a lo que roundTo2DP(m) debería devolver. Si el valor exacto de m es 0.014999999999999999944488848768742172978818416595458984375, pero su representación de cadena es ''0.015'', ¿cuál es la respuesta correcta : matemática, práctica, filosóficamente, o lo que sea, cuando lo redondeamos a dos decimales?

No hay una sola respuesta correcta a esto. Depende de su caso de uso. Probablemente quiera respetar la representación de String y redondear hacia arriba cuando:

  • El valor que se representa es intrínsecamente discreto, por ejemplo, una cantidad de moneda en una moneda de 3 decimales como los dinares. En este caso, el valor verdadero de un Número como 0.015 es 0.015, y la representación 0.0149999999 ... que se obtiene en un punto flotante binario es un error de redondeo. (Por supuesto, muchos argumentarán, razonablemente, que debe usar una biblioteca decimal para manejar dichos valores y nunca representarlos como números binarios de punto flotante en primer lugar).
  • El valor fue escrito por un usuario. En este caso, nuevamente, el número decimal exacto ingresado es más ''verdadero'' que la representación de punto flotante binario más cercana.

Por otro lado, es probable que desee respetar el valor del punto flotante binario y redondear hacia abajo cuando su valor proviene de una escala inherentemente continua, por ejemplo, si se trata de una lectura de un sensor.

Estos dos enfoques requieren un código diferente. Para respetar la representación de la Cadena del Número, podemos (con un poco de código razonablemente sutil) implementar nuestro propio redondeo que actúa directamente en la representación de la Cadena, dígito por dígito, usando el mismo algoritmo que usaría en la escuela cuando Se les enseñó a redondear los números. A continuación se muestra un ejemplo que respeta el requisito del OP de representar el número con 2 decimales "solo cuando sea necesario" eliminando los ceros finales después del punto decimal; Por supuesto, es posible que tenga que ajustarlo a sus necesidades específicas.

/** * Converts num to a decimal string (if it isn''t one already) and then rounds it * to at most dp decimal places. * * For explanation of why you''d want to perform rounding operations on a String * rather than a Number, see http://.com/a/38676273/1709587 * * @param {(number|string)} num * @param {number} dp * @return {string} */ function roundStringNumberWithoutTrailingZeroes (num, dp) { if (arguments.length != 2) throw new Error("2 arguments required"); num = String(num); if (num.indexOf(''e+'') != -1) { // Can''t round numbers this large because their string representation // contains an exponent, like 9.99e+37 throw new Error("num too large"); } if (num.indexOf(''.'') == -1) { // Nothing to do return num; } var parts = num.split(''.''), beforePoint = parts[0], afterPoint = parts[1], shouldRoundUp = afterPoint[dp] >= 5, finalNumber; afterPoint = afterPoint.slice(0, dp); if (!shouldRoundUp) { finalNumber = beforePoint + ''.'' + afterPoint; } else if (/^9+$/.test(afterPoint)) { // If we need to round up a number like 1.9999, increment the integer // before the decimal point and discard the fractional part. finalNumber = Number(beforePoint)+1; } else { // Starting from the last digit, increment digits until we find one // that is not 9, then stop var i = dp-1; while (true) { if (afterPoint[i] == ''9'') { afterPoint = afterPoint.substr(0, i) + ''0'' + afterPoint.substr(i+1); i--; } else { afterPoint = afterPoint.substr(0, i) + (Number(afterPoint[i]) + 1) + afterPoint.substr(i+1); break; } } finalNumber = beforePoint + ''.'' + afterPoint; } // Remove trailing zeroes from fractional part before returning return finalNumber.replace(/0+$/, '''') }

Ejemplo de uso:

> roundStringNumberWithoutTrailingZeroes(1.6, 2) ''1.6'' > roundStringNumberWithoutTrailingZeroes(10000, 2) ''10000'' > roundStringNumberWithoutTrailingZeroes(0.015, 2) ''0.02'' > roundStringNumberWithoutTrailingZeroes(''0.015000'', 2) ''0.02'' > roundStringNumberWithoutTrailingZeroes(1, 1) ''1'' > roundStringNumberWithoutTrailingZeroes(''0.015'', 2) ''0.02'' > roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2) ''0.02'' > roundStringNumberWithoutTrailingZeroes(''0.01499999999999999944488848768742172978818416595458984375'', 2) ''0.01''

La función anterior es probablemente lo que desea usar para evitar que los usuarios que presencian números que ingresaron se redondeen de forma incorrecta.

(Como alternativa, también puede probar la biblioteca github.com/jhohlfeld/round10 que proporciona una función de comportamiento similar con una implementación muy diferente).

Pero, ¿qué sucede si tiene el segundo tipo de Número, un valor tomado de una escala continua, donde no hay razón para pensar que las representaciones decimales aproximadas con menos lugares decimales son más precisas que las que tienen más? En ese caso, no queremos respetar la representación de String, porque esa representación (como se explica en la especificación) ya está más o menos redondeada; no queremos cometer el error de decir "0.014999999 ... 375 rondas hasta 0.015, que se redondea hasta 0.02, así que 0.014999999 ... 375 rondas hasta 0.02".

Aquí simplemente podemos usar el método toFixed para toFixed . Tenga en cuenta que al llamar a Number() en el String devuelto por toFixed , obtenemos un Number cuya representación de String no tiene ceros finales (gracias a la forma en que JavaScript calcula la representación de String de un Number, que se explicó anteriormente en esta respuesta).

/** * Takes a float and rounds it to at most dp decimal places. For example * * roundFloatNumberWithoutTrailingZeroes(1.2345, 3) * * returns 1.234 * * Note that since this treats the value passed to it as a floating point * number, it will have counterintuitive results in some cases. For instance, * * roundFloatNumberWithoutTrailingZeroes(0.015, 2) * * gives 0.01 where 0.02 might be expected. For an explanation of why, see * http://.com/a/38676273/1709587. You may want to consider using the * roundStringNumberWithoutTrailingZeroes function there instead. * * @param {number} num * @param {number} dp * @return {number} */ function roundFloatNumberWithoutTrailingZeroes (num, dp) { var numToFixedDp = Number(num).toFixed(dp); return Number(numToFixedDp); }


La manera más fácil:

+num.toFixed(2)

Lo convierte en una cadena y, a continuación, de nuevo en un entero / float.


La respuesta de MarkG es la correcta. Aquí hay una extensión genérica para cualquier número de lugares decimales.

Number.prototype.round = function(places) { return +(Math.round(this + "e+" + places) + "e-" + places); }

Uso:

var n = 1.7777; n.round(2); // 1.78

Prueba de unidad:

it.only(''should round floats to 2 places'', function() { var cases = [ { n: 10, e: 10, p:2 }, { n: 1.7777, e: 1.78, p:2 }, { n: 1.005, e: 1.01, p:2 }, { n: 1.005, e: 1, p:0 }, { n: 1.77777, e: 1.8, p:1 } ] cases.forEach(function(testCase) { var r = testCase.n.round(testCase.p); assert.equal(r, testCase.e, ''didn/'t get right number''); }); })


Pruebe esta solución ligera :

function round(x, digits){ return parseFloat(x.toFixed(digits)) } round(1.222, 2) ; // 1.22 round(1.222, 10) ; // 1.222


Puedes usar

function roundToTwo(num) { return +(Math.round(num + "e+2") + "e-2"); }

Encontré esto en MDN . Su forma de evitar el problema con 1.005 que se mentioned .

roundToTwo(1.005) 1.01 roundToTwo(10) 10 roundToTwo(1.7777777) 1.78 roundToTwo(9.1) 9.1 roundToTwo(1234.5678) 1234.57


Si el valor es un tipo de texto:

parseFloat("123.456").toFixed(2);

Si el valor es un número:

var numb = 123.23454; numb = numb.toFixed(2);

Hay una desventaja de que valores como 1.5 darán "1.50" como salida. Una solución sugerida por @minitech:

var numb = 1.5; numb = +numb.toFixed(2); // Note the plus sign that drops any "extra" zeroes at the end. // It changes the result (which is a string) into a number again (think "0 + foo"), // which means that it uses only as many digits as necessary.

Parece que Math.round es una mejor solución. ¡Pero no lo es! En algunos casos NO se redondeará correctamente:

Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01!

toFixed () tampoco se redondeará correctamente en algunos casos (probado en Chrome v.55.0.2883.87)!

Ejemplos:

parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56. parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56. // However, it will return correct result if you round 1.5551. parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected. 1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356. // However, it will return correct result if you round 1.35551. 1.35551.toFixed(2); // Returns 1.36 as expected.

Supongo que esto se debe a que 1.555 es en realidad algo así como flotar 1.55499994 detrás de escena.

La solución 1 es usar un script con el algoritmo de redondeo requerido, por ejemplo:

function roundNumber(num, scale) { if(!("" + num).includes("e")) { return +(Math.round(num + "e+" + scale) + "e-" + scale); } else { var arr = ("" + num).split("e"); var sig = "" if(+arr[1] + scale > 0) { sig = "+"; } return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale); } }

https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview

La solución 2 es evitar los cálculos de front-end y extraer valores redondeados del servidor backend.


Un método de redondeo preciso. Fuente: MDN

(function(){ /** * Decimal adjustment of a number. * * @param {String} type The type of adjustment. * @param {Number} value The number. * @param {Integer} exp The exponent (the 10 logarithm of the adjustment base). * @returns {Number} The adjusted value. */ function decimalAdjust(type, value, exp) { // If the exp is undefined or zero... if (typeof exp === ''undefined'' || +exp === 0) { return Math[type](value); } value = +value; exp = +exp; // If the value is not a number or the exp is not an integer... if (isNaN(value) || !(typeof exp === ''number'' && exp % 1 === 0)) { return NaN; } // Shift value = value.toString().split(''e''); value = Math[type](+(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)); } // Decimal round if (!Math.round10) { Math.round10 = function(value, exp) { return decimalAdjust(''round'', value, exp); }; } // Decimal floor if (!Math.floor10) { Math.floor10 = function(value, exp) { return decimalAdjust(''floor'', value, exp); }; } // Decimal ceil if (!Math.ceil10) { Math.ceil10 = function(value, exp) { return decimalAdjust(''ceil'', value, exp); }; } })();

Ejemplos:

// Round Math.round10(55.55, -1); // 55.6 Math.round10(55.549, -1); // 55.5 Math.round10(55, 1); // 60 Math.round10(54.9, 1); // 50 Math.round10(-55.55, -1); // -55.5 Math.round10(-55.551, -1); // -55.6 Math.round10(-55, 1); // -50 Math.round10(-55.1, 1); // -60 Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above // Floor Math.floor10(55.59, -1); // 55.5 Math.floor10(59, 1); // 50 Math.floor10(-55.51, -1); // -55.6 Math.floor10(-51, 1); // -60 // Ceil Math.ceil10(55.51, -1); // 55.6 Math.ceil10(51, 1); // 60 Math.ceil10(-55.59, -1); // -55.5 Math.ceil10(-59, 1); // -50


Uno puede usar .toFixed(NumberOfDecimalPlaces) .

var str = 10.234.toFixed(2); // => ''10.23'' var number = Number(str); // => 10.23


Utilice Math.round(num * 100) / 100


Ninguna de las respuestas encontradas aquí es correcta . @stinkycheeseman pidió que se redondeara , ustedes redondearon el número.

Para redondear, usa esto:

Math.ceil(num * 100)/100;


Aquí hay un método prototipo:

Number.prototype.round = function(places){ places = Math.pow(10, places); return Math.round(this * places)/places; } var yournum = 10.55555; yournum = yournum.round(2);


En general, el redondeo se realiza mediante escalado: round(num / p) * p

Usar la notación exponencial maneja el redondeo de números + ve, correctamente. Sin embargo, este método no puede redondear los casos de borde correctamente.

function round(num, precision = 2) { var scaled = Math.round(num + "e" + precision); return Number(scaled + "e" + -precision); } // testing some edge cases console.log( round(1.005, 2) ); // 1.01 correct console.log( round(2.175, 2) ); // 2.18 correct console.log( round(5.015, 2) ); // 5.02 correct console.log( round(-1.005, 2) ); // -1 wrong console.log( round(-2.175, 2) ); // -2.17 wrong console.log( round(-5.015, 2) ); // -5.01 wrong

Aquí, también hay una función que escribí para hacer correctamente el redondeo aritmético. Puedes probarlo tú mismo.

/** * MidpointRounding away from zero (''arithmetic'' rounding) * Uses a half-epsilon for correction. (This offsets IEEE-754 * half-to-even rounding that was applied at the edge cases). */ function RoundCorrect(num, precision = 2) { // half epsilon to correct edge cases. var c = 0.5 * Number.EPSILON * num; // var p = Math.pow(10, precision); //slow var p = 1; while (precision--> 0) p *= 10; if (num < 0) p *= -1; return Math.round((num + c) * p) / p; } // testing some edge cases console.log(RoundCorrect(1.005, 2)); // 1.01 correct console.log(RoundCorrect(2.175, 2)); // 2.18 correct console.log(RoundCorrect(5.015, 2)); // 5.02 correct console.log(RoundCorrect(-1.005, 2)); // -1.01 correct console.log(RoundCorrect(-2.175, 2)); // -2.18 correct console.log(RoundCorrect(-5.015, 2)); // -5.02 correct



Para no lidiar con muchos 0s, usa esta variante:

Math.round(num * 1e2) / 1e2



Si está utilizando la biblioteca de lodash, puede usar el método redondo de lodash como se muestra a continuación.

_.round(number, precision)

P.ej:

_.round(1.7777777, 2) = 1.78


Una forma más simple de ES6 es

const round = (x, n) => parseFloat(Math.round(x * Math.pow(10, n)) / Math.pow(10, n)).toFixed(n);

Este patrón también devuelve la precisión solicitada.

ex:

round(44.7826456, 4) // yields 44.7826 round(78.12, 4) // yields 78.1200


Use algo como esto "parseFloat (parseFloat (value) .toFixed (2))"

parseFloat(parseFloat("1.7777777").toFixed(2))-->1.78 parseFloat(parseFloat("10").toFixed(2))-->10 parseFloat(parseFloat("9.1").toFixed(2))-->9.1


Desde ES6, hay una forma "adecuada" (sin anular las estadísticas y crear soluciones) para hacerlo utilizando toPrecision

var x = 1.49999999999; console.log(x.toPrecision(4)); console.log(x.toPrecision(3)); console.log(x.toPrecision(2)); var y = Math.PI; console.log(y.toPrecision(6)); console.log(y.toPrecision(5)); console.log(y.toPrecision(4)); var z = 222.987654 console.log(z.toPrecision(6)); console.log(z.toPrecision(5)); console.log(z.toPrecision(4));


Hay un par de maneras de hacer eso. Para gente como yo, la variante de Lodash.

function round(number, precision) { var pair = (number + ''e'').split(''e'') var value = Math.round(pair[0] + ''e'' + (+pair[1] + precision)) pair = (value + ''e'').split(''e'') return +(pair[0] + ''e'' + (+pair[1] - precision)) }

Uso:

round(0.015, 2) // 0.02 round(1.005, 2) // 1.01

Si su proyecto utiliza jQuery o lodash, también puede encontrar el roundmétodo adecuado en las bibliotecas.

Actualización 1

Quité la variante n.toFixed(2), porque no es correcta. Gracias @ avalanche1


MarkG y Lavamantis ofrecieron una solución mucho mejor que la aceptada. ¡Es una pena que no tengan más votos!

Aquí está la función que utilizo para resolver los problemas de decimales de punto flotante también basados ​​en MDN . Es incluso más genérico (pero menos conciso) que la solución de Lavamantis:

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

Úsalo con:

round(10.8034, 2); // Returns 10.8 round(1.275, 2); // Returns 1.28 round(1.27499, 2); // Returns 1.27 round(1.2345678e+2, 2); // Returns 123.46

En comparación con la solución de Lavamantis, podemos hacer ...

round(1234.5678, -2); // Returns 1200 round("123.45"); // Returns 123


Para mí, MDN no estaba dando la respuesta correcta. He encontrado que toFixed funciona mejor. A continuación se muestran ejemplos de ambos:

console.log(Math.round(43000 / 80000) * 100); // wrong answer console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer



Una forma de lograr dicho redondeo solo si es necesario es usar Number.prototype.toLocaleString() :

myNumber.toLocaleString(''en'', {maximumFractionDigits:2, useGrouping:false})

Esto proporcionará exactamente la salida que espera, pero como cadenas. Aún puede convertirlos de nuevo a números si ese no es el tipo de datos que espera.


+(10).toFixed(2); // = 10 +(10.12345).toFixed(2); // = 10.12 (10).toFixed(2); // = 10.00 (10.12345).toFixed(2); // = 10.12


var roundUpto = function(number, upto){ return Number(number.toFixed(upto)); } roundUpto(0.1464676, 2);

toFixed(2) aquí 2 es el número de dígitos hasta el cual queremos redondear este número.