Una caja de herramientas de métodos estáticos
java.lang.Math es una clase llena de funciones matemáticas ya hechas: potencias, raíces, valores absolutos, redondeo, trigonometría, logaritmos y números aleatorios. Dos cosas la hacen fácil de usar:
- Está en
java.lang, que todo archivo Java importa automáticamente. No hay que escribir ninguna líneaimport. - Todos los métodos son
static. Los llamas sobre el nombre de la clase,Math.sqrt(25), y nunca creas un objetoMath. La página de miembros estáticos explica qué significastatic.
Fíjate en que algunos resultados se imprimen con .0 y otros no. Cada método de Math tiene un tipo de retorno fijo, y conocerlo es casi todo lo que hay que aprender sobre esta clase.
| Método | Qué hace | Devuelve |
|---|---|---|
Math.pow(a, b) | a elevado a b | double |
Math.sqrt(x) | raíz cuadrada | double |
Math.cbrt(x) | raíz cúbica | double |
Math.abs(x) | valor absoluto | el mismo tipo que x |
Math.max(a, b) / Math.min(a, b) | el mayor / el menor de dos | el más amplio de los dos tipos |
Math.round(x) | número entero más cercano | long para un double, int para un float |
Math.floor(x) / Math.ceil(x) | redondear hacia abajo / hacia arriba | double |
Math.random() | número aleatorio desde 0.0 hasta 1.0 | double |
Math.PI, Math.E | las constantes π y e | double |
Math.pow: potencias
Math.pow(base, exponent) eleva un número a una potencia. Recibe dos parámetros double y devuelve un double, aunque le pases números enteros:
Para guardar el resultado en un int, haz un cast con (int). Para potencias enteras pequeñas el resultado double es exacto, así que el cast da la respuesta correcta. El problema aparece con resultados grandes: un double por encima de Integer.MAX_VALUE (2147483647) se convierte exactamente en Integer.MAX_VALUE, así que (int) Math.pow(2, 40) da 2147483647. Para potencias mayores haz el cast a long, y recuerda que por encima de 2⁵³ un double no puede representar exactamente todos los números enteros. La página de conversión de tipos explica qué le hace un cast al valor.
Java no tiene operador de potencia. 2 ^ 3 compila, pero ^ es el XOR bit a bit, y el resultado es 1, no 8. Es uno de los errores de principiante más comunes en el código matemático de Java.
Un double de diez millones o más se imprime en notación científica, lo que sorprende la primera vez que imprimes una potencia de diez:
1.0E7 significa 1.0 × 10⁷. El valor es el mismo; solo cambia la forma de imprimirlo. Haz un cast a long, o formatea con String.format("%.0f", value), para imprimirlo como dígitos normales.
Math.sqrt y Math.cbrt: raíces
Math.sqrt(x) devuelve la raíz cuadrada de x como un double. Math.cbrt(x) devuelve la raíz cúbica.
La raíz cuadrada de un número negativo no es un número real, así que Math.sqrt(-4) devuelve NaN ("not a number", no es un número) en lugar de lanzar una excepción. NaN se propaga por cualquier operación en la que participe, así que comprueba las entradas antes de calcular una raíz si pueden llegar valores negativos. Math.hypot(a, b) calcula sqrt(a*a + b*b) directamente, una forma habitual de obtener la distancia entre dos puntos.
Math.abs: valor absoluto
Math.abs(x) quita el signo. A diferencia de pow y sqrt, devuelve el mismo tipo que le das: un int para un int, un double para un double.
El uso habitual es una diferencia en la que te importa el tamaño y no la dirección, como la distancia entre dos posiciones.
Math.max y Math.min
Math.max(a, b) devuelve el mayor de dos valores y Math.min(a, b) el menor. Reciben exactamente dos argumentos. Para tres o más, anida las llamadas:
Cuando los dos argumentos tienen tipos distintos, el más estrecho se amplía primero. Math.max(3, 7.5) compara dos valores double y devuelve un double. El último ejemplo limita un valor al rango de 0 a 100: Math.min lo deja como máximo en 100 y Math.max evita que baje de 0.
Redondeo: round, floor, ceil
Java tiene tres métodos de redondeo, y se diferencian tanto en la dirección como en el tipo de retorno:
Math.roundva al número entero más cercano. Un valor justo en la mitad se redondea hacia arriba, hacia el infinito positivo, así que2.5pasa a3y-2.5pasa a-2. Devuelve unlongpara un argumentodouble(y unintpara unfloat).Math.floorsiempre redondea hacia abajo, hacia el infinito negativo, y devuelve undouble.Math.ceilsiempre redondea hacia arriba, hacia el infinito positivo, y devuelve undouble.- Un cast
(int)no redondea en absoluto: descarta la parte decimal, lo que baja los números positivos y sube los negativos.
Como Math.round(double) devuelve un long, asignarlo a un int no compila sin un cast:
int n = Math.round(2.6); // error: incompatible types: possible lossy conversion from long to int
int m = (int) Math.round(2.6); // OK, m vale 3
long k = Math.round(2.6); // OK
Para redondear a un número de decimales, multiplica, redondea y vuelve a dividir. Dividir entre 100.0 (un double) en lugar de 100 conserva los decimales:
La segunda línea divide un long entre un int, lo que es división entera, así que se pierden los decimales. Cuando solo necesitas mostrar un número redondeado, String.format("%.2f", value) es más sencillo y no cambia el valor guardado.
Math.random: números aleatorios
Math.random() devuelve un double mayor o igual que 0.0 y menor que 1.0. El valor es distinto en cada llamada, así que la salida de los programas de esta sección cambia cada vez que pulsas Run.
Para obtener un número entero en un rango, estira ese valor, haz el cast y desplázalo. Para un número entero de min a max, ambos incluidos:
int value = (int) (Math.random() * (max - min + 1)) + min;
Así funciona para un dado, donde min es 1 y max es 6:
Math.random() * 6da undoubledesde0.0hasta6.0, sin incluir6.0.(int)descarta la parte decimal y da uno de0, 1, 2, 3, 4, 5.+ 1lo desplaza a1, 2, 3, 4, 5, 6.
La primera línea muestra cinco tiradas aleatorias. La segunda comprueba diez mil tiradas y, en la práctica, siempre imprime lowest: 1, highest: 6: la fórmula alcanza los dos extremos del rango y nunca los supera.
Los paréntesis alrededor de Math.random() * (max - min + 1) importan. Un cast se aplica al valor que tiene justo después, así que (int) Math.random() * 6 convierte primero Math.random(). Eso siempre es 0, y 0 * 6 es 0, así que todas las "tiradas" salen iguales.
Math.random() está bien para juegos y ejercicios. Para algo más, la clase java.util.Random y ThreadLocalRandom.current().nextInt(min, max + 1) (en java.util.concurrent) devuelven enteros directamente, y Random admite una semilla para repetir la misma secuencia en las pruebas. Ninguno de ellos sirve para contraseñas ni tokens de seguridad; para eso usa java.security.SecureRandom.
Math.PI y Math.E
Math.PI (π) y Math.E (el número de Euler, e) son constantes static final double:
Úsalas en lugar de escribir 3.14. Son tan precisas como permite un double, y el nombre le dice al lector qué número es.
Resultados enteros frente a resultados double
La mayoría de los métodos de Math reciben y devuelven double. Cuando les pasas valores int, Java amplía automáticamente los argumentos a double, pero la aritmética que escribes antes de la llamada sigue haciéndose en int. De ahí sale la mayoría de las respuestas incorrectas:
items / perBox es 7 / 2, y dividir dos valores int descarta el resto, así que vale 3 antes de que Math.ceil llegue a verlo. Math.ceil(3.0) es 3.0. Haz que uno de los operandos sea un double, con un cast o con un literal como 4.0, para que la división conserve su parte decimal. La página de operadores explica la división entera con más detalle.
La regla general: decide qué tipo quieres al final, haz que la división o la multiplicación se calculen en double cuando importen los decimales, y vuelve a int o long con un solo cast, al final.
Otros métodos útiles
Algunos métodos más de la misma clase, todos llamados de la misma forma:
Math.loges el logaritmo natural;Math.log10es en base 10.Math.floorMod(a, b)da un resto con el signo deb, que es lo que quieres para dar la vuelta dentro de un rango, como los días de la semana. El operador%conserva el signo dea.- Los métodos trigonométricos (
sin,cos,tan) reciben radianes. Convierte antes los grados conMath.toRadians. Math.addExact,Math.multiplyExacty sus métodos hermanos lanzan unaArithmeticExceptioncuando hay desbordamiento, en lugar de dar la vuelta en silencio hasta un número negativo.
Preguntas frecuentes
¿Cómo se usa Math.pow en Java?
Math.pow(base, exponent) devuelve base elevado a exponent como un double, así que Math.pow(2, 3) es 8.0. Para guardar el resultado en un int, haz un cast: int n = (int) Math.pow(2, 10); da 1024. Java no tiene operador de potencia ^; ^ es el XOR bit a bit.
¿Cómo genero un número aleatorio en un rango con Math.random?
Math.random() devuelve un double desde 0.0 hasta 1.0, sin incluir 1.0. Para un número entero de min a max, ambos incluidos, usa (int) (Math.random() * (max - min + 1)) + min. Una tirada de dado es (int) (Math.random() * 6) + 1.
¿Hay que importar la clase Math en Java?
No. Math está en el paquete java.lang, que todo archivo Java importa automáticamente. Todos sus métodos son static, así que los llamas sobre el nombre de la clase, como en Math.sqrt(16), sin crear ningún objeto.
¿Por qué Math.round devuelve un long en Java?
Math.round(double) devuelve un long porque un double puede contener valores mucho mayores que un int. Asignar el resultado a un int requiere un cast: int n = (int) Math.round(2.6);. Math.round(float) devuelve un int.
¿Cuál es la diferencia entre Math.floor, Math.ceil y Math.round?
Math.floor redondea hacia abajo (2.7 pasa a 2.0, -2.3 pasa a -3.0), Math.ceil redondea hacia arriba (2.1 pasa a 3.0) y Math.round va al número entero más cercano, con las mitades hacia arriba (2.5 pasa a 3). floor y ceil devuelven un double; round devuelve un long.