Cómo redondear números hacia arriba, hacia abajo o al más cercano
Controla cómo JavaScript redondea números decimales al formatear con diferentes modos de redondeo
Introducción
Cuando formateas números para mostrar, a menudo necesitas redondear valores decimales. Un precio de $2.567 necesita convertirse en $2.57. Una medida de 3.891 metros podría mostrarse como 4 metros. La forma en que redondeas estos números afecta la precisión, las expectativas del usuario y la lógica de negocio.
Diferentes situaciones requieren diferentes estrategias de redondeo. A veces necesitas redondear hacia arriba para asegurarte de cobrar lo suficiente por un producto. A veces necesitas redondear hacia abajo para mantenerte dentro de un presupuesto. La mayoría de las veces, redondeas al valor más cercano para mantener la precisión.
JavaScript proporciona nueve modos de redondeo diferentes a través de la API Intl.NumberFormat. Estos modos controlan cómo se redondean los números cuando caen entre dos valores posibles. Esta lección explica los tres modos de redondeo más comunes y muestra cuándo usar los demás.
Cómo redondea JavaScript los números por defecto
Cuando formateas un número sin especificar un modo de redondeo, JavaScript usa una estrategia llamada halfExpand. Este modo redondea los valores al valor más cercano posible, y cuando un número cae exactamente a la mitad entre dos valores, redondea alejándose de cero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0
});
console.log(formatter.format(2.4));
// Output: "2"
console.log(formatter.format(2.5));
// Output: "3"
console.log(formatter.format(2.6));
// Output: "3"
El valor 2.4 está más cerca de 2 que de 3, por lo que se redondea hacia abajo a 2. El valor 2.6 está más cerca de 3 que de 2, por lo que se redondea hacia arriba a 3. El valor 2.5 cae exactamente a la mitad entre 2 y 3, por lo que el modo halfExpand lo redondea alejándose de cero a 3.
Este comportamiento predeterminado coincide con lo que la mayoría de las personas aprenden en la escuela y esperan en los cálculos cotidianos. Distribuye los errores de redondeo de manera uniforme en muchos cálculos, lo que lo hace adecuado para el formateo de números de propósito general.
Entender qué significa alejarse de cero
La frase "alejarse de cero" describe la dirección del redondeo para números que caen exactamente a medio camino entre dos valores posibles. Para números positivos, redondear alejándose de cero significa redondear hacia arriba. Para números negativos, redondear alejándose de cero significa redondear hacia abajo aumentando la magnitud.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0
});
console.log(formatter.format(2.5));
// Output: "3"
console.log(formatter.format(-2.5));
// Output: "-3"
Tanto 2,5 como -2,5 se redondean alejándose de cero. Para 2,5, alejarse de cero significa hacia el infinito positivo, produciendo 3. Para -2,5, alejarse de cero significa hacia el infinito negativo, produciendo -3. En ambos casos, la magnitud aumenta.
Redondear hacia arriba con ceil
El modo de redondeo ceil siempre redondea hacia el infinito positivo. Para números positivos, esto significa redondear hacia arriba. Para números negativos, esto significa redondear hacia cero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "ceil"
});
console.log(formatter.format(2.1));
// Output: "3"
console.log(formatter.format(2.9));
// Output: "3"
console.log(formatter.format(-2.1));
// Output: "-2"
console.log(formatter.format(-2.9));
// Output: "-2"
Este modo es útil cuando necesitas asegurar que un número nunca sea menor de lo necesario. Por ejemplo, si calculas que una caja puede contener 2,3 artículos, necesitas 3 cajas. Si calculas que una tarea toma 1,1 días, necesitas planificar 2 días.
const boxFormatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "ceil"
});
const itemsPerBox = 5;
const totalItems = 12;
const boxesNeeded = totalItems / itemsPerBox;
console.log(boxFormatter.format(boxesNeeded));
// Output: "3"
El cálculo produce 2,4 cajas, pero no puedes pedir una fracción de caja. Redondear hacia arriba asegura que tengas suficiente capacidad.
Redondear hacia abajo con floor
El modo de redondeo floor siempre redondea hacia el infinito negativo. Para números positivos, esto significa redondear hacia abajo. Para números negativos, esto significa redondear alejándose de cero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "floor"
});
console.log(formatter.format(2.1));
// Output: "2"
console.log(formatter.format(2.9));
// Output: "2"
console.log(formatter.format(-2.1));
// Output: "-3"
console.log(formatter.format(-2.9));
// Output: "-3"
Este modo es útil cuando necesitas estimaciones conservadoras o cuando quieres mantenerte dentro de los límites. Por ejemplo, si tienes un presupuesto de $100,87, podrías mostrarlo como $100 para evitar gastar accidentalmente de más.
const budgetFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
maximumFractionDigits: 0,
roundingMode: "floor"
});
const availableBudget = 100.87;
console.log(budgetFormatter.format(availableBudget));
// Output: "$100"
Redondear hacia abajo garantiza que el importe mostrado siempre sea alcanzable con el presupuesto real.
Redondeando al más cercano con halfExpand
Aunque halfExpand es el modo predeterminado, puedes especificarlo explícitamente para dejar clara tu intención en el código. Este modo redondea al valor más cercano y maneja los casos intermedios redondeando alejándose de cero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 1,
roundingMode: "halfExpand"
});
console.log(formatter.format(2.14));
// Output: "2.1"
console.log(formatter.format(2.15));
// Output: "2.2"
console.log(formatter.format(2.16));
// Output: "2.2"
El valor 2.14 está más cerca de 2.1, por lo que se redondea a 2.1. El valor 2.16 está más cerca de 2.2, por lo que se redondea a 2.2. El valor 2.15 cae exactamente a mitad de camino, por lo que se redondea alejándose de cero a 2.2.
Este modo funciona bien para la mayoría de las tareas de formateo de números porque minimiza el error total de redondeo en múltiples cálculos. Cada valor intermedio tiene la misma probabilidad de estar en el lado positivo o negativo de cero, por lo que la dirección de redondeo se equilibra con el tiempo.
Combinando modos de redondeo con dígitos fraccionarios
Los modos de redondeo funcionan junto con la configuración de dígitos fraccionarios para controlar el resultado final. La opción maximumFractionDigits determina cuántos decimales aparecen, y el roundingMode determina cómo manejar valores que caen entre números representables.
const ceilFormatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
roundingMode: "ceil"
});
console.log(ceilFormatter.format(10.001));
// Output: "$10.01"
console.log(ceilFormatter.format(10.999));
// Output: "$11.00"
Con dos decimales, 10.001 necesita redondearse a 10.00 o 10.01. El modo ceil redondea hacia arriba, produciendo 10.01. El valor 10.999 se redondea hacia arriba a 11.00.
Redondeando hacia cero con trunc
El modo de redondeo trunc redondea hacia cero, lo que significa que elimina la parte fraccionaria del número. Para números positivos, redondea hacia abajo. Para números negativos, redondea hacia arriba.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "trunc"
});
console.log(formatter.format(2.1));
// Output: "2"
console.log(formatter.format(2.9));
// Output: "2"
console.log(formatter.format(-2.1));
// Output: "-2"
console.log(formatter.format(-2.9));
// Output: "-2"
Este modo trunca efectivamente la porción decimal. Es útil cuando deseas mostrar solo la parte entera de un número sin considerar el valor fraccionario para propósitos de redondeo.
Redondeo alejándose de cero con expand
El modo de redondeo expand redondea alejándose de cero. Para números positivos, esto redondea hacia arriba. Para números negativos, redondea hacia abajo a una magnitud mayor.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "expand"
});
console.log(formatter.format(2.1));
// Output: "3"
console.log(formatter.format(2.9));
// Output: "3"
console.log(formatter.format(-2.1));
// Output: "-3"
console.log(formatter.format(-2.9));
// Output: "-3"
Este modo asegura que el redondeo siempre aumente la magnitud del número. Puede ser útil en contextos financieros donde deseas ser conservador en una dirección que favorezca la precisión sobre la subestimación.
Comprender los modos de redondeo intermedio
Los cinco modos que comienzan con half redondean al valor más cercano, pero difieren en cómo manejan los casos intermedios exactos. Estos modos te dan un control preciso sobre el comportamiento de desempate cuando los valores caen exactamente entre dos números representables.
El modo halfCeil redondea los valores intermedios hacia el infinito positivo.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfCeil"
});
console.log(formatter.format(2.5));
// Output: "3"
console.log(formatter.format(-2.5));
// Output: "-2"
El modo halfFloor redondea los valores intermedios hacia el infinito negativo.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfFloor"
});
console.log(formatter.format(2.5));
// Output: "2"
console.log(formatter.format(-2.5));
// Output: "-3"
El modo halfTrunc redondea los valores intermedios hacia cero.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfTrunc"
});
console.log(formatter.format(2.5));
// Output: "2"
console.log(formatter.format(-2.5));
// Output: "-2"
El modo halfEven redondea los valores intermedios al número par más cercano. Este modo a veces se denomina redondeo bancario porque reduce el sesgo en los cálculos financieros.
const formatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 0,
roundingMode: "halfEven"
});
console.log(formatter.format(2.5));
// Output: "2"
console.log(formatter.format(3.5));
// Output: "4"
console.log(formatter.format(4.5));
// Output: "4"
El valor 2,5 se redondea a 2 porque 2 es par. El valor 3,5 se redondea a 4 porque 4 es par. El valor 4,5 también se redondea a 4 porque 4 es par.
Elegir un modo de redondeo para tu aplicación
El modo de redondeo que elijas depende de tus requisitos empresariales y la naturaleza de los datos que muestras. Diferentes contextos requieren diferentes estrategias.
Utiliza ceil cuando necesites asegurar suficiencia. La planificación de capacidad, los recuentos de inventario y las estimaciones de tiempo a menudo requieren redondear hacia arriba para garantizar recursos adecuados.
Utiliza floor cuando necesites mantenerte dentro de los límites. La visualización de presupuestos, el seguimiento de cuotas y los cálculos de descuentos a menudo requieren redondear hacia abajo para evitar exceder los recursos disponibles.
Utiliza halfExpand para visualización de propósito general donde la precisión importa pero la precisión extrema no es crítica. Este es el valor predeterminado por una razón y funciona bien para la mayoría de las tareas de formateo de números.
Utiliza halfEven para cálculos financieros donde necesitas minimizar el sesgo de redondeo acumulativo. Este modo garantiza que, a lo largo de muchos cálculos, los errores de redondeo no favorezcan consistentemente una dirección.
Utiliza trunc cuando quieras mostrar solo la parte entera de un número sin aplicar lógica de redondeo a la parte fraccionaria.
Uso de modos de redondeo con formato de moneda
Los modos de redondeo interactúan de forma natural con el formato de moneda. Diferentes negocios tienen diferentes reglas sobre cómo redondear valores de moneda, y la opción roundingMode te permite implementar esas reglas.
const retailPrice = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
roundingMode: "ceil"
});
const wholesalePrice = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
roundingMode: "floor"
});
const calculatedPrice = 19.874;
console.log(retailPrice.format(calculatedPrice));
// Output: "$19.88"
console.log(wholesalePrice.format(calculatedPrice));
// Output: "$19.87"
Un minorista podría redondear los precios hacia arriba para garantizar la rentabilidad, mientras que un mayorista podría redondear hacia abajo para mantenerse competitivo. El mismo precio calculado produce diferentes valores mostrados según las reglas de negocio codificadas en el modo de redondeo.