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?
javascript
rounding
decimal-point
apestoso
fuente
fuente
Number.EPSILON
. UsoMath.round( num * 100 + Number.EPSILON ) / 100
.Number.EPSILON
aquí?Respuestas:
Utilizar
Math.round(num * 100) / 100
Editar: para garantizar que cosas como 1.005 redondeen correctamente, utilizamos
Math.round((num + Number.EPSILON) * 100) / 100
fuente
Math.round((num + 0.00001) * 100) / 100
. ProbarMath.round((1.005 + 0.00001) * 100) / 100
yMath.round((1.0049 + 0.00001) * 100) / 100
Si el valor es un tipo de texto:
Si el valor es un número:
Hay una desventaja de que valores como 1.5 darán "1.50" como salida. Una solución sugerida por @minitech:
Parece que
Math.round
es una mejor solución. ¡Pero no lo es! En algunos casos NO se redondeará correctamente:toFixed () también NO ronda correctamente en algunos casos (probado en Chrome v.55.0.2883.87)!
Ejemplos:
Supongo que esto se debe a que 1.555 es en realidad algo así como flotante 1.55499994 detrás de escena.
La solución 1 es usar un script con el algoritmo de redondeo requerido, por ejemplo:
https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
NOTA: Esta no es una solución universal para todos. Existen varios algoritmos de redondeo diferentes, su implementación puede ser diferente, depende de sus requisitos. https://en.wikipedia.org/wiki/Rounding
La solución 2 es evitar los cálculos frontales y extraer valores redondeados del servidor de fondo.
fuente
parseFloat(number.toFixed(decimalPlaces));
@PerLundbergparseFloat("55.555").toFixed(2)
vuelve"55.55"
en la consola de desarrollo de Chrome.Puedes usar
Encontré esto en MDN . Su manera evita el problema con 1.005 que se mencionó .
fuente
+(val)
es el equivalente de coerción del usoNumber(val)
. Concatenar "e-2" a un número resultó en una cadena que necesitaba ser convertida de nuevo a un número.roundToTwo(1.0049999999999999)
aparece como 1.01 (inevitablemente, desde entonces1.0049999999999999 == 1.005
). Me parece que el flotante que obtienes si escribesnum = 1.005
'obviamente' 'debería' redondearse a 1.00, porque el valor exacto de num es menor que 1.005. Por supuesto, también me parece que la cadena '1.005' 'obviamente' 'debería' redondearse a 1.01. El hecho de que diferentes personas parezcan tener diferentes intuiciones sobre cuál es el comportamiento correcto real aquí es parte de por qué es complicado.1.0049999999999999
y1.005
, por definición, son el mismo número. Esto se llama un corte dedekind.1.00499 < 1.005
estrue
,1.0049999999999999 < 1.005
evalúa afalse
.La respuesta de MarkG es la correcta. Aquí hay una extensión genérica para cualquier número de decimales.
Uso:
Prueba de unidad:
fuente
function round(number, decimals) { return +(Math.round(number + "e+" + decimals) + "e-" + decimals); }
(-1.005).round(2) === -1
Deberías usar:
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 declararon.
Esa es simplemente la forma en que los números de coma flotante funcionan en una computadora. Como el 99% de los lenguajes de programación, JavaScript no tiene números de coma flotante hechos en casa ; para eso depende de la CPU / FPU. Una computadora usa binario, y en binario, no hay números como
0.1
, sino una mera aproximación binaria para eso. ¿Por qué? Por la misma razón que 1/3 no puede escribirse en decimal: su valor es 0.33333333 ... con un infinito de tres.Aquí vienen
Number.EPSILON
. Ese número es la diferencia entre 1 y el siguiente número existente en los números de coma flotante de doble precisión. Eso es todo: no hay un número entre1
y 1 +Number.EPSILON
.EDITAR:
Como se preguntó 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 algún error de coma flotante delta.No es útil cuando el valor proviene de una fuente directa (por ejemplo, literal, entrada del usuario o sensor).
EDITAR (2019):
Como @maganap y algunas personas han señalado, es mejor agregar
Number.EPSILON
antes de multiplicar:EDITAR (diciembre de 2019):
Últimamente, utilizo una función similar a esta para comparar números con epsilon:
Mi caso de uso es una afirmación + validación de datos lib que estoy desarrollando durante muchos años.
De hecho, en el código que estoy usando
ESPILON_RATE = 1 + 4 * Number.EPSILON
yEPSILON_ZERO = 4 * Number.MIN_VALUE
(cuatro veces el épsilon), porque quiero un verificador de igualdad lo suficientemente suelto como para acumular un error de coma flotante.Hasta ahora, se ve perfecto para mí. Espero que sea de ayuda.
fuente
Math.round( (num + Number.EPSILON) * 100) / 100
.. También estoy de acuerdo en que este es el método correcto para redondear correctamente (aunque no es exactamente lo que se preguntó en esta pregunta).0.004999999999999999
como resultado un error de coma flotante compuesto y el resultado matemáticamente correcto fue probablemente 0.005. Si es una lectura de un sensor? No tanto.Math.round(1.5)
= 2, peroMath.round(-1.5)
= -1. Entonces esto es perfectamente consistente. Aquí -1 es mayor que -2, al igual que -1000 es mayor que -1000.01. No debe confundirse con mayores números absolutos .Se puede usar
.toFixed(NumberOfDecimalPlaces)
.fuente
+(1.005).toFixed(2)
cuál devuelve en1
lugar de1.01
.Number(9).toFixed(2).replace(/0+$/, '')
=> "9."Esta pregunta es complicada.
Supongamos que tenemos una función,
roundTo2DP(num)
que toma un flotador 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 deberían 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 entre 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 se puede implementar para dar esas respuestas obvias, porque los tres números que se le pasan son el mismo número . Los números de punto flotante binario 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 exactamente0.01499999999999999944488848768742172978818416595458984375
que está más cerca de 0.01 que de 0.02.
Puede ver que los tres números son iguales en la consola de su navegador, en el shell de nodo u otro intérprete de JavaScript. Solo compáralos:
Entonces, cuando escribo
m = 0.0150000000000000001
, el valor exacto con elm
que termino está más cerca de0.01
lo que está0.02
. Y sin embargo, si me conviertom
en una cadena ...... obtengo 0.015, que debería redondear a 0.02, y que notablemente no es el número de 56 decimales que dije anteriormente que todos estos números eran exactamente iguales. Entonces, ¿qué magia oscura es esta?
La respuesta se puede encontrar en la especificación ECMAScript, en la sección 7.1.12.1: ToString aplicado al tipo Number . Aquí se establecen las reglas para convertir un número m en una cadena. La parte clave es el punto 5, en el que se genera un número entero s cuyos dígitos se utilizarán en la representación de cadena de m :
La parte clave aquí es el requisito de que " k es lo más pequeño posible". Lo que equivale a ese requisito es un requisito que, dado un Número
m
, el valor deString(m)
debe tener el menor número posible de dígitos sin dejar de cumplir el requisito de queNumber(String(m)) === m
. Como ya sabemos eso0.015 === 0.0150000000000000001
, ahora está claro por quéString(0.0150000000000000001) === '0.015'
debe ser cierto.Por supuesto, nada de esta discusión ha respondido directamente lo que
roundTo2DP(m)
debería regresar. Sim
el valor exacto es 0.01499999999999999944488848768742172978818416595458984375, pero su representación de cadena es '0.015', entonces cuál es el correcto respuesta , matemática, práctica, filosófica o lo que sea, cuando redondeamos a dos decimales?No hay una única respuesta correcta a esto. Depende de su caso de uso. Probablemente desee respetar la representación de cadena y redondear hacia arriba cuando:
Por otro lado, es probable que desee respetar el valor de punto flotante binario y redondear hacia abajo cuando su valor proviene de una escala inherentemente continua, por ejemplo, si es 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 sobre la representación de la cadena, dígito a dígito, utilizando el mismo algoritmo que hubiera utilizado en la escuela cuando se les enseñó a redondear números. A continuación se muestra un ejemplo que respeta el requisito del OP de representar el número a 2 decimales "solo cuando sea necesario" quitando los ceros finales después del punto decimal; puede, por supuesto, necesitar ajustarlo a sus necesidades precisas.
Ejemplo de uso:
La función anterior es probablemente lo que desea usar para evitar que los usuarios sean testigos de que los números que ingresaron se redondearon incorrectamente.
(Como alternativa, también puede probar la biblioteca 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 decimales son más precisas que las que tienen más? En ese caso, no queremos respetar la representación de cadena, porque esa representación (como se explica en la especificación) ya está redondeada; no queremos cometer el error de decir "0.014999999 ... 375 redondea a 0.015, que redondea a 0.02, entonces 0.014999999 ... 375 redondea a 0.02".
Aquí podemos simplemente usar el
toFixed
método incorporado . Tenga en cuenta que al invocarNumber()
la Cadena devuelta portoFixed
, obtenemos un Número cuya representación de Cadena no tiene ceros finales (gracias a la forma en que JavaScript calcula la representación de Cadena de un Número, discutido anteriormente en esta respuesta).fuente
roundStringNumberWithoutTrailingZeroes(362.42499999999995, 2)
. Resultado esperado (como en PHPecho round(362.42499999999995, 2)
):362.43
. Resultado real:362.42
round
da 362.43. Eso parece intuitivamente incorrecto, ya que 362.42499999999995 es inferior a 362.425 (en matemáticas y en código,362.42499999999995 < 362.425
es cierto tanto en JS como en PHP). La respuesta de PHP tampoco minimiza la distancia entre los números de coma flotante originales y redondeados, desde entonces362.43 - 362.42499999999995 > 362.42499999999995 - 362.42
. De acuerdo con php.net/manual/en/function.round.php , PHPround
sigue el estándar C99; Tendré que aventurarme en la tierra de C para entender lo que está sucediendo.Considere
.toFixed()
y.toPrecision()
:http://www.javascriptkit.com/javatutors/formatnumber.shtml
fuente
Un método de redondeo preciso. Fuente: Mozilla.
Ejemplos:
fuente
Math.round10(3544.5249, -2)
devuelve 3544.52 en lugar de 3544.533544.5249
a 2 decimales es3544.52
(error = 0.0049). Si lo fuera3544.53
, el error sería 0.0051. Está realizando redondeos sucesivos, es decir, Math.round10 (Math.round10 (3544.5249, -3), -2), lo que da un error de redondeo mayor y, por lo tanto, no es deseable.number += 0.00011
Math.round10( Math.round10(3544.5249, -3) , -2)
Ninguna de las respuestas encontradas aquí es correcta . @stinkycheeseman pidió redondear , todos redondearon el número.
Para redondear, use esto:
fuente
Math.ceil(1.1 * 100)/100;
regresa1.11
, porque 1.1 * 100 está de110.00000000000001
acuerdo con los nuevos navegadores modernos Firefox, Chrome, Safari y Opera ... IE, a la antigua usanza, todavía piensa1.1*100=1100
.Math.ceil(num.toFixed(4) * 100) / 100
Math.ceil((1.1).toFixed(4) * 100) / 100
también regresará1.11
en Firefox, el problema / error de los navegadores modernos es la multiplicación y la gente debería saberlo (por ejemplo, trabajé en un juego de lotería esa vez).Aquí hay una manera simple de hacerlo:
Sin embargo, es posible que desee seguir adelante y hacer una función separada para hacerlo por usted:
Entonces simplemente pasarías el valor.
Puede mejorarlo para redondear a cualquier número arbitrario de decimales agregando un segundo parámetro.
fuente
fuente
+(0.015).toFixed(2) == 0.01
.Para mí Math.round () no estaba dando la respuesta correcta. Descubrí que toFixed (2) funciona mejor. A continuación hay ejemplos de ambos:
fuente
1.005
.(1.005).toFixed(2)
todavía resulta a1.00
.Usa esta función
Number(x).toFixed(2);
fuente
Number
nuevo, si no desea que se devuelva como una cadena:Number(Number(x).toFixed(2));
Number
llamada no es necesaria,x.toFixed(2)
funciona.(1).toFixed(2)
regresa1.00
, pero se necesita un interrogador1
en este caso.1.005.toFixed(2)
rinde"1"
cuando debería ser"1.01"
.2017
Solo usa código nativo
.toFixed()
Si necesita ser estricto y agregar dígitos solo si es necesario, puede usar
replace
fuente
toFixed
sugerido por múltiples respuestas años antes que la suya, sino que no cumple con la condición de "solo si es necesario" en la pregunta;(1).toFixed(2)
da"1.00"
donde el autor de la pregunta deseaba"1"
.Prueba este peso ligero solución :
fuente
return Number(x.toFixed(digits))
?.toFixed()
que solo permite números de todos modos.round(1.005, 2)
ver un resultado de en1
lugar de1.01
.round(0.995, 2) => 0.99
;round(1.006, 2) => 1.01
;round(1.005, 2) => 1
Hay un par de formas de hacerlo. Para personas como yo, la variante de Lodash
Uso:
Si su proyecto usa jQuery o lodash, también puede encontrar el
round
método adecuado en las bibliotecas.Actualización 1
Eliminé la variante
n.toFixed(2)
porque no es correcta. Gracias @ avalanche1fuente
Number.toFixed()
devolverá una cadena pero con un símbolo más antes, el intérprete JS convertirá la cadena en un número. Esta es una sintaxis de azúcar.alert((+1234).toFixed(2))
muestra "1234.00".alert(+1234.toFixed(2))
lanzaSyntaxError: identifier starts immediately after numeric literal
. Me quedo con la primera opción.362.42499999999995
. Resultado esperado (como en PHPecho round(362.42499999999995, 2)
):362.43
. Resultado real:362.42
Si está usando la biblioteca lodash, puede usar el método redondo de lodash como el siguiente.
P.ej:
fuente
Desde ES6 hay una forma 'adecuada' (sin anular las estadísticas y crear soluciones) para hacer esto usando toPrecision
entonces puedes simplemente
parseFloat
y los ceros 'desaparecerán'.Sin embargo, no resuelve el 'problema de redondeo 1.005', ya que es intrínseco a cómo se procesan las fracciones flotantes .
Si está abierto a las bibliotecas, puede usar bignumber.js
fuente
(1.005).toPrecision(3)
Todavía regresa en1.00
lugar de en1.01
realidad.toPrecision
devuelve una cadena que cambia el tipo de salida deseado..toPrecision
método, es una especificidad de los números de coma flotante (que son los números en JS) - intente1.005 - 0.005
, volverá0.9999999999999999
.(1).toPrecision(3)
devuelve '1.00', pero el interlocutor quería tenerlo1
en este caso.toPrecision
hace el formato, no el último, y no es una respuesta a la pregunta del OP, aunque al principio parezca relevante, se equivoca mucho. Ver en.wikipedia.org/wiki/Significant_figures . Por ejemploNumber(123.4).toPrecision(2)
devoluciones"1.2e+2"
yNumber(12.345).toPrecision(2)
devoluciones"12"
. También estoy de acuerdo con el punto de @ adamduren de que devuelve una cadena que no es deseable (no es un gran problema pero no deseable).MarkG y Lavamantis ofrecieron una solución mucho mejor que la que ha sido aceptada. ¡Es una pena que no reciban más votos!
Aquí está la función que uso para resolver los problemas de decimales de punto flotante también basados en MDN . Es aún más genérico (pero menos conciso) que la solución de Lavamantis:
Úselo con:
En comparación con la solución de Lavamantis, podemos hacer ...
fuente
Esto puede ayudarlo a:
para más información, puedes echar un vistazo a este enlace
Math.round (num) vs num.toFixed (0) e inconsistencias del navegador
fuente
El enfoque más fácil sería usar toFixed y luego eliminar los ceros finales con la función Number:
fuente
15.00
? Los números en JS no almacenan los lugares decimales y cualquier pantalla trunca automáticamente el exceso de lugares decimales (cualquier cero al final).toFixed(2)
aquí 2 es el número de dígitos hasta el que queremos redondear este número.fuente
Puede funcionar para ti
para saber la diferencia entre toFixed y round. Puede echar un vistazo a Math.round (num) vs num.toFixed (0) y las inconsistencias del navegador .
fuente
La manera más fácil:
+num.toFixed(2)
Lo convierte en una cadena y luego de nuevo en un entero / flotante.
fuente
toFixed()
a 3. Así sería+num.toFixed(3)
. Eso está funcionando de la manera en que se supone que es, 1.005 se redondea a 1.00, que es igual a 1Aquí hay un método prototipo:
fuente
Use algo como esto "parseFloat (parseFloat (value) .toFixed (2))"
fuente
Una forma de lograr dicho redondeo solo si es necesario es usar Number.prototype.toLocaleString () :
Esto proporcionará exactamente el resultado que espera, pero como cadenas. Todavía puede convertirlos de nuevo en números si ese no es el tipo de datos que espera.
fuente
toLocaleString
.Después de ejecutar varias iteraciones de todas las formas posibles para lograr una precisión de redondeo decimal verdadera y precisa, está claro que la solución más precisa y eficiente es usar Number.EPSILON. Esto proporciona una verdadera solución matemática al problema de la precisión matemática de coma flotante. Se puede rellenar fácilmente como se muestra aquí: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON para admitir a todos los últimos usuarios restantes de IE (quizás nuevamente debería dejar de hacer eso).
Adaptado de la solución proporcionada aquí: https://stackoverflow.com/a/48850944/6910392
Una solución simple de caída que proporciona redondeo decimal preciso, piso y techo, con una variable de precisión opcional sin agregar una biblioteca completa.
ACTUALIZACIÓN: Como Sergey señaló en los comentarios, hay una limitación para este (o cualquier) método que valga la pena señalar. En el caso de números como 0.014999999999999999, seguirá experimentando imprecisiones que son el resultado de alcanzar el límite absoluto de las limitaciones de precisión para el almacenamiento de valores de coma flotante. No hay matemática u otra solución que se pueda aplicar para dar cuenta de eso, ya que el valor en sí mismo se evalúa inmediatamente como 0.015. Puede confirmar esto simplemente invocando ese valor por sí mismo en la consola. Debido a esta limitación, ni siquiera sería posible utilizar la manipulación de cadenas para reducir este valor, ya que su representación de cadenas es simplemente "0.015". Cualquier solución para explicar esto debería aplicarse lógicamente en la fuente de los datos antes de aceptar el valor en un script,
fuente
Esta es la solución más simple y elegante (y yo soy el mejor del mundo):
fuente
E
notación.roundToX(362.42499999999995, 2)
. Resultado esperado (como en PHPecho round(362.42499999999995, 2)
):362.43
. Resultado real:362.42