Cómo redondear números en Java: Math.round(), decimales, BigDecimal y RoundingMode

目次

1. Qué significa “Redondeo (四捨五入)” en Java

Cuando quieres hacer “redondeo (四捨五入)” en Java, en realidad no existe un único método que siempre redondee como esperas.
Esto se debe a que en Java, el enfoque de redondeo apropiado depende del tipo numérico (int / double / BigDecimal, etc.) y del objetivo (cálculo vs. visualización).

En esta sección, primero organizaremos los conceptos clave y aclararemos por qué el redondeo en Java puede resultar confuso.

1.1 Regla básica de redondeo (5 y más redondea hacia arriba)

La regla general de redondeo es la siguiente:

  • Si el dígito siguiente es 5 o mayor → redondear hacia arriba
  • Si el dígito siguiente es 4 o menor → redondear hacia abajo

Ejemplo (redondeo a la unidad)

  • 1.4 → 1
  • 1.5 → 2

Esta regla es la misma en Java, pero el verdadero desafío es “qué método aplica esta regla” y “cuántos dígitos puedes manejar”.

En Java, el redondeo suele separarse por propósito, como por ejemplo:

  • Solo quieres redondear un número simple
  • Quieres redondear al n‑ésimo decimal
  • Necesitas tolerancia cero al error (por ejemplo, cálculos monetarios)

Si intentas manejar todo esto con el mismo enfoque, a menudo obtendrás resultados no deseados.

1.2 Por qué el redondeo en Java puede resultar confuso

Las principales razones por las que el redondeo en Java se describe a menudo como “difícil” o “no funciona como se espera” son estos tres puntos:

Razón 1: Errores de precisión de punto flotante (double)

double es un tipo que representa decimales en binario.
Como resultado, incluso los números que se ven limpios en decimal pueden incluir errores internos de precisión.

Ejemplo:

double x = 0.1 + 0.2;
System.out.println(x); // 0.30000000000000004

Si redondeas en este estado, puedes obtener resultados que no coinciden con la intuición humana.

Razón 2: No puedes “redondear directamente al n‑ésimo decimal”

Java no proporciona un método dedicado como:
“redondear a 2 decimales”
de forma nativa.

Por lo tanto, en muchos casos necesitas una ajuste mediante aritmética, como por ejemplo:

  • Multiplicar por 10 o 100
  • Redondear
  • Escalar de nuevo a la magnitud original

Si cometes un error en los pasos, el resultado será incorrecto.

Razón 3: Los métodos difieren en comportamiento y tipos de retorno

Por ejemplo, Math.round() es cómodo, pero devuelve un tipo entero (int / long).
Si deseas redondear manteniendo los decimales, no puedes usarlo tal cual.

Trampas comunes y cosas a tener en cuenta

  • Asumir que “redondear = Math.round()” → A menudo insuficiente para 2 o más decimales o cálculos monetarios
  • Realizar cálculos monetarios con double y redondear después → Los errores pueden acumularse y volverse riesgosos en sistemas reales
  • Usar el mismo redondeo para visualización y cálculo → Puedes perder precisión al redondear cálculos internos

El redondeo es un proceso para “limpiar la salida final”, y el momento y el tipo de dato al que lo apliques son extremadamente importantes.

2. Redondeo con Math.round() (el enfoque más básico)

Math.round() es uno de los métodos más básicos y sencillos para redondear en Java.
Es un buen primer enfoque para principiantes, pero necesitas comprender sus casos de uso válidos y limitaciones para evitar un uso incorrecto.

En esta sección, organizaremos el uso correcto de Math.round() y las trampas comunes que probablemente encontrarás en el desarrollo real.

2.1 Uso básico de Math.round()

Math.round() redondea el número dado al entero más cercano.

double a = 1.4;
double b = 1.5;

System.out.println(Math.round(a)); // 1
System.out.println(Math.round(b)); // 2

Puntos clave:

  • Redondea hacia arriba cuando la parte fraccionaria es 0.5 o mayor
  • Redondea hacia abajo cuando es menor que 0.5
  • Sigue la regla estándar de “round‑half‑up”

Parece intuitivo, pero el tipo de retorno es un punto importante a vigilar.

2.2 Atención: el tipo de retorno es int / long

Math.round() cambia su tipo de retorno según el tipo del argumento.

Argument typeReturn type
floatint
doublelong

Ejemplo:

double x = 3.7;
long result = Math.round(x);

El punto clave es: el valor de retorno siempre es de tipo entero.

En otras palabras, no es adecuado tal cual para casos como:

  • Quieres mantener decimales en el resultado
  • Quieres mantener 1 o 2 decimales

porque Math.round() en sí produce un entero.

Ejemplo de error común

double price = 12.34;
double rounded = Math.round(price); // actually long → assigned to double

Este código no genera un error de compilación, pero
la parte fraccionaria se pierde por completo y se convierte en 12.0, así que ten cuidado.

2.3 Cómo redondear al segundo decimal o más allá (técnica ×10 / ×100)

Si deseas usar Math.round() para redondear al enésimo decimal,
normalmente sigues este proceso:

Pasos

  1. Multiplica el valor objetivo por 10ⁿ
  2. Redondea a un entero con Math.round()
  3. Divide por 10ⁿ para volver a la escala original

Ejemplo: Redondear a 2 decimales

double value = 1.234;
double rounded = Math.round(value * 100) / 100.0;

System.out.println(rounded); // 1.23

Ejemplo: Redondear a 1 decimal

double value = 1.25;
double rounded = Math.round(value * 10) / 10.0;

System.out.println(rounded); // 1.3

Este enfoque es sencillo, pero no elimina por completo los problemas de precisión específicos de double.

Trampas, advertencias y errores comunes

  • División entera accidental Math.round(value * 100) / 100; // 100 es int → los decimales desaparecen → Siempre usa un double como 100.0
  • Usarlo directamente para cálculos monetarios → Está bien para mostrar, pero a menudo no es adecuado para cálculos
  • Redondear demasiado pronto → Si redondeas resultados intermedios, el valor final puede desviarse

Math.round() es excelente cuando “solo quieres un entero” o “quieres redondear para mostrar”, pero debes recordar que
tiene limitaciones cuando la precisión es crítica.

3. Una forma común de redondear al enésimo decimal

Solicitudes como “Quiero redondear a 2 decimales” o “Quiero mantener 3 decimales” son extremadamente comunes, y
esto también es la intención principal de búsqueda detrás de la palabra clave java 四捨五入.

En esta sección, explicaremos un enfoque común para redondear al enésimo decimal usando Math.round(),
y señalaremos claramente sus limitaciones.

3.1 El patrón de fórmula básica

Debido a que Java no ofrece un método dedicado para redondear al enésimo decimal,
un enfoque muy usado es escalar el número, redondearlo y luego volver a escalarlo.

Fórmula básica

Math.round(value × 10^n) ÷ 10^n

Ejemplo: Redondear a 2 decimales

double value = 12.345;
double rounded = Math.round(value * 100) / 100.0;

System.out.println(rounded); // 12.35

Ejemplo: Redondear a 3 decimales

double value = 12.34567;
double rounded = Math.round(value * 1000) / 1000.0;

System.out.println(rounded); // 12.346

Este método es fácil de entender y es lo suficientemente práctico para procesamiento de números solo para mostrar.

3.2 Un caso donde no funciona bien (el problema 0.1 + 0.2)

Sin embargo, este método no puede evitar por completo los errores de precisión de double.

Un ejemplo clásico es el siguiente caso:

double value = 0.1 + 0.2;
double rounded = Math.round(value * 10) / 10.0;

System.out.println(value);   // 0.30000000000000004
System.out.println(rounded); // 0.3

Puede parecer correcto aquí, pero dependiendo del cálculo y del número de dígitos, aún puedes obtener resultados de redondeo inesperados.

Los siguientes casos son especialmente riesgosos:

  • Cálculos monetarios
  • Cálculos acumulativos de tasas impositivas o porcentajes
  • Redondear repetidamente dentro de bucles

3.3 Por qué ocurren los errores (explicación muy breve)

double es un tipo de punto flotante que representa decimales en binario.
Así que incluso valores que son exactos en base 10 pueden incluir pequeños errores en su representación interna.

Esto es un detalle de la especificación de Java, no un error.

Malentendidos comunes

  • “Mi fórmula está equivocada” → ❌
  • “Java está roto” → ❌
  • “Se debe a la naturaleza del double” → ✅

Problemas, advertencias y errores comunes

  • Obtener el orden de escalado/división incorrecto Math.round(value) * 100 / 100.0; // sin sentido
  • Usar un entero en la división Math.round(value * 100) / 100; // los decimales desaparecen
  • Redondear repetidamente durante pasos intermedios → hace que los errores se acumulen más fácilmente

Este método es “fácil y rápido”, pero debes entender que puede ser insuficiente cuando se requiere precisión.

4. Redondeo preciso con BigDecimal (recomendado)

Para cálculos de dinero, cálculos de impuestos y otros flujos de trabajo donde no se aceptan errores, redondear con double y Math.round() no es apropiado.

En esos casos, el enfoque recomendado es usar BigDecimal.
BigDecimal es una clase que puede manejar números en base 10 con precisión, y es la solución estándar en Java para “redondeo preciso”.

4.1 Cuándo debe usar BigDecimal

Debes usar BigDecimal para casos como los siguientes:

  • Cálculos monetarios (precios, facturas, saldos)
  • Cálculos basados en tasas, como impuestos y tipos de interés
  • Contabilidad, finanzas y sistemas empresariales
  • Procesos donde los resultados del redondeo deben ser reproducibles

Si el resultado del cálculo en sí importa (no solo la visualización), es más seguro elegir BigDecimal en lugar de double.

4.2 La forma correcta de crear BigDecimal (new vs valueOf)

El error más común con BigDecimal es crearlo de forma incorrecta.

❌ Ejemplo incorrecto (no recomendado)

BigDecimal bd = new BigDecimal(1.23);

Esto traslada el error de precisión del double.

✅ Ejemplos correctos (recomendado)

BigDecimal bd1 = new BigDecimal("1.23");
BigDecimal bd2 = BigDecimal.valueOf(1.23);
  • Constructor con String: la opción más segura
  • valueOf: seguro porque convierte internamente mediante String

Regla práctica: evita new BigDecimal(double).

4.3 Cómo usar setScale() y RoundingMode

Para redondear con BigDecimal, normalmente combinas setScale() con RoundingMode.

Ejemplo: Redondear a 2 decimales

import java.math.BigDecimal;
import java.math.RoundingMode;

BigDecimal value = new BigDecimal("12.345");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP);

System.out.println(rounded); // 12.35
  • 1.º argumento: número de decimales a conservar
  • 2.º argumento: regla de redondeo

RoundingMode.HALF_UP corresponde a la regla típica de “redondear a la mitad hacia arriba” (5 y superiores redondean hacia arriba).

Problemas, advertencias y errores comunes

  • No especificar RoundingMode value.setScale(2); // puede lanzar una excepción
  • Realizar double → BigDecimal → redondeo en el orden incorrecto → usa BigDecimal desde el principio
  • Confundir visualización con cálculo → usa BigDecimal para el cálculo; formatea solo al mostrar

BigDecimal añade más código, pero es esencial siempre que la precisión y la seguridad sean la máxima prioridad.

5. Tipos y diferencias de RoundingMode

Al redondear con BigDecimal, el concepto clave que debes comprender es RoundingMode (modo de redondeo).

RoundingMode define explícitamente “qué regla usar”, y en la práctica debe considerarse obligatorio, porque no especificarlo hace que el comportamiento sea ambiguo.

5.1 HALF_UP (Redondeo típico)

RoundingMode.HALF_UP corresponde a la definición más común de redondeo.

Regla

  • Si el siguiente dígito es 5 o mayor → redondear hacia arriba
  • Si el siguiente dígito es 4 o menor → redondear hacia abajo

Ejemplo

BigDecimal value = new BigDecimal("2.345");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP);

System.out.println(rounded); // 2.35

Si no tienes una razón especial, elegir HALF_UP para redondear suele ser lo correcto.

5.2 Cómo difiere de HALF_DOWN / HALF_EVEN

RoundingMode incluye varios estilos de redondeo con nombres similares.
Muchas personas se confunden, así que aclararemos las diferencias.

HALF_DOWN

  • Si el siguiente dígito es exactamente 5, redondear hacia abajo
    2.345 → 2.34
    

HALF_EVEN (redondeo bancario)

  • Si el siguiente dígito es exactamente 5, redondear al número par más cercano
    2.345 → 2.34
    2.355 → 2.36
    

HALF_EVEN se usa para reducir el sesgo sistemático del redondeo y puede especificarse en normas financieras o estadísticas, pero no es necesario para la mayoría de los casos de negocio generales y para código orientado a principiantes.

5.3 Cómo elegir

Si no estás seguro, la regla de decisión es sencilla:

  • Redondeo típico → HALF_UP
  • Dominio financiero/regulado con una norma definida → seguir la especificación
  • Sin razón especial → solo HALF_UP

Errores comunes

  • “Usar HALF_EVEN solo porque sí”
  • “Copiar‑pegar sin entender la diferencia”

Los modos de redondeo son parte de la especificación de tu sistema.
No deberías cambiarlos sin una razón clara.

Trampas, advertencias y errores comunes

  • Omitir RoundingMode → puede provocar excepciones en tiempo de ejecución
  • Asumir que el redondeo siempre es HALF_UP → puede entrar en conflicto con especificaciones de negocio
  • Reglas de redondeo no estandarizadas dentro del equipo → puede generar resultados de cálculo inconsistentes

6. Trampas comunes, advertencias y ejemplos de fallos

El redondeo en Java es un área donde es fácil cometer errores incluso si conoces la sintaxis y las API.
En esta sección resumiremos los errores que suelen cometer los desarrolladores principiantes e intermedios, y explicaremos claramente “por qué está mal” y “cómo evitarlo”.

6.1 Realizar cálculos monetarios con double

Este es tanto el error más común como el más peligroso.

double price = 1000.0;
double tax = price * 0.1;
double total = price + tax;

Puede parecer correcto a primera vista, pero
como double es un tipo que puede incluir errores de precisión,
introduce el riesgo de obtener resultados incorrectos en cálculos de dinero.

Mentalidad correcta

  • Para cálculo: BigDecimal
  • Para visualización: redondeo/formateo
    BigDecimal price = new BigDecimal("1000");
    BigDecimal tax = price.multiply(new BigDecimal("0.1"));
    BigDecimal total = price.add(tax);
    

6.2 Obtener el orden de redondeo incorrecto

Con el redondeo, cuándo lo aplicas importa.

❌ Mal ejemplo

double a = Math.round(x * 100) / 100.0;
double b = Math.round(a * y * 100) / 100.0;

Si redondeas repetidamente durante pasos intermedios, los errores se acumulan.

✅ Directriz básica

  • Completa todos los cálculos primero
  • Aplica el redondeo solo una vez al resultado final

6.3 Mezclar redondeo de visualización con redondeo de cálculo

Si confundes “redondeo para visualización” con “redondeo para cálculos internos”, tu diseño se romperá.

Malentendidos comunes

  • Usar un valor redondeado para visualización en el siguiente cálculo
  • Cambiar la lógica de cálculo para adaptarse a requisitos de la UI

Separación correcta

  • Cálculo interno: priorizar la precisión (BigDecimal)
  • Visualización: formateo/redondeo

6.4 No estandarizar RoundingMode

Si diferentes partes de tu código usan una mezcla de
HALF_UP, HALF_DOWN y HALF_EVEN, puedes terminar con resultados inconsistentes de la misma operación.

Contramedidas

  • Definir la regla de redondeo como una constante
  • Estandarizarla en todo el equipo/proyecto
    static final RoundingMode ROUND_MODE = RoundingMode.HALF_UP;
    

Resumen de trampas comunes

  • Solo porque double “puede calcular” no significa que sea “preciso”
  • Redondea solo una vez, al final
  • Trata las reglas de redondeo como parte de tu especificación
  • Separa cálculo y visualización

Mantener esto en mente te ayuda a evitar la mayoría de los problemas relacionados con el redondeo.

7. Referencia rápida: Qué método usar (según caso de uso)

Como se ha explicado hasta ahora, Java tiene múltiples formas de redondear números, y lo importante no es “cuál es la correcta”, sino que
la elección adecuada depende del caso de uso.

En esta sección organizaremos la selección práctica de métodos por escenario para que los lectores puedan decidir rápidamente.

7.1 Si quieres un entero simple → Math.round()

Casos de uso típicos

  • Necesitas mostrar un valor calculado como entero
  • Recuentos, número de personas, puntos de puntuación, etc.
  • Procesamiento donde los errores de precisión no son un problema

Enfoque recomendado

long result = Math.round(value);

Notas

  • El tipo de retorno es int o long
  • No es adecuado si necesitas conservar decimales

👉 Si “solo quieres un entero”, usa Math.round().

7.2 Si quieres mostrar hasta N decimales → Math.round() + Escalado

Casos de uso típicos

  • Números para la interfaz de usuario
  • Informes y salida de logs
  • Situaciones donde no se requiere precisión estricta

Enfoque recomendado (2 decimales)

double rounded = Math.round(value * 100) / 100.0;

Notas

  • Los errores de precisión de double siguen presentes
  • No lo uses para datos de cálculo

👉 Aceptable solo para visualización

7.3 Dinero, impuestos, lógica de negocio → BigDecimal + HALF_UP

Casos de uso típicos

  • Dinero, facturación, pagos
  • Tasas de impuestos y descuentos
  • Lógica de negocio y datos persistidos

Enfoque recomendado

BigDecimal rounded =
    value.setScale(2, RoundingMode.HALF_UP);

Por qué

  • Maneja números base‑10 con precisión
  • Hace explícitas las reglas de redondeo
  • Garantiza reproducibilidad

👉 Este es, de hecho, el enfoque estándar en sistemas del mundo real

7.4 Un flujo de decisión simple cuando no estás seguro

  • “¿Es aceptable algún error?” wp:list /wp:list

    • SÍ → enfoques basados en Math.round()
    • NO → BigDecimal
    • “¿Guardarás/reusarás el resultado?” wp:list /wp:list

    • SÍ → BigDecimal

    • NO (solo visualización) → Math.round()

Errores comunes (selección de método)

  • Reutilizar código solo para visualización en lógica de negocio
  • Continuar usando double para valores monetarios
  • Abusar de Math.round() “porque es fácil”

Una vez que organices la selección de métodos, puedes reducir significativamente el costo de futuros cambios de especificación y correcciones de errores.

FAQ (Preguntas frecuentes)

Q1. ¿Cuál es la forma más fácil de redondear en Java?

R. Si simplemente deseas redondear a un entero, Math.round() es la forma más fácil. Sin embargo, el tipo de retorno es un entero, por lo que no puedes conservar decimales.

Q2. ¿Cómo redondeo a 2 decimales (o al n‑ésimo decimal)?

R. Para fines de visualización, escala el número así:
Math.round(value * 100) / 100.0
Si necesitas precisión, usa BigDecimal.setScale().

Q3. ¿Por qué los resultados se desvían aunque use Math.round()?

R. Esto se debe a errores de precisión de punto flotante en double. Es parte del comportamiento de Java, no un error.

Q4. ¿Debo evitar Math.round() para cálculos monetarios?

R. Sí, no se recomienda. Para dinero e impuestos es más seguro usar BigDecimal y redondear con RoundingMode.HALF_UP.

Q5. Estoy usando BigDecimal pero aún veo errores a veces

R. Puede que estés usando new BigDecimal(double).
Utiliza new BigDecimal("1.23") o BigDecimal.valueOf(1.23) en su lugar.

Q6. ¿Qué RoundingMode debo elegir?

R. Para el redondeo típico, RoundingMode.HALF_UP es una opción segura por defecto. Si tu dominio tiene una norma o especificación definida, síguela.

Q7. ¿Está bien redondear durante cálculos intermedios?

R. No se recomienda. Redondear en pasos intermedios hace que los errores se acumulen, por lo que la regla básica es aplicarlo solo al resultado final.

Q8. ¿Debo separar el redondeo para visualización del redondeo para cálculos?

R. Sí.

  • Para cálculos: BigDecimal (primero la precisión)
  • Para visualización: Math.round() o formateo

Separarlos es el diseño correcto.