Cómo verificar si la raíz cuadrada de un número es un entero: 5 métodos en Java

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: el problema que explota Stack Overflow

\n\n

Imagina: estás escribiendo código que procesa miles de números por segundo. Necesitas filtrar aquellos cuya raíz cuadrada es un número entero (1, 4, 9, 16…). Parece sencillo, ¿verdad? Tomas Math.sqrt(), verificas el residuo y listo. Pero no todo es tan simple.

\n\n

La pregunta «Fastest way to determine if an integer's square root is an integer» en Stack Overflow ya ha acumulado más de 100 000 visitas. ¿Por qué? Porque Math.sqrt() es una operación de punto flotante, lo que la hace lenta y propensa a errores de redondeo. Para números grandes (por ejemplo, 2^50), el double puede simplemente «mentir».

\n\n

En este artículo, analizaremos 5 enfoques en Java: desde el más ingenuo hasta algoritmos rápidos que utilizan operaciones de bits y aritmética de enteros. Descubrirás qué método es realmente más rápido y cuál es más seguro. ¡Allá vamos!

\n\n

Planteamiento del problema

\n\n

Necesitamos escribir un método boolean isPerfectSquare(long n) que devuelva true si n es un cuadrado perfecto. Ejemplos:

\n
    \n
  • isPerfectSquare(25) → true (5*5)
  • \n
  • isPerfectSquare(26) → false
  • \n
  • isPerfectSquare(0) → true (0*0)
  • \n
  • isPerfectSquare(1) → true
  • \n
\n

Probaremos con long, ya que int es un caso particular y long ofrece más margen para errores.

\n\n

Método 1: Ingenuo — Math.sqrt + verificación del residuo

\n\n

La forma más simple que se le ocurre a un principiante:

\n\n
public static boolean isPerfectSquareSqrt(long n) {\n    if (n < 0) return false;\n    double sqrt = Math.sqrt(n);\n    long floorSqrt = (long) sqrt;\n    return floorSqrt * floorSqrt == n;\n}\n
\n\n

Problema n.º 1: Precisión. Para números mayores a ~2^53 (9 007 199 254 740 991), el double deja de representar enteros con exactitud. Ejemplo: n = 999999999999999999L — Math.sqrt devolverá un resultado incorrecto.

\n\n

Problema n.º 2: Velocidad. Math.sqrt es una instrucción de CPU (FSQRT), pero sigue siendo más lenta que operaciones aritméticas simples.

\n\n

Cuándo usarlo: Solo para int o long pequeños (< 10^12), donde la velocidad no sea crítica.

\n\n

Método 2: Raíz cuadrada entera mediante Newton-Raphson

\n\n

El método de Newton (Newton-Raphson) es una forma clásica de calcular la raíz cuadrada sin números de punto flotante. Refinamos la aproximación de forma iterativa:

\n\n
public static boolean isPerfectSquareNewton(long n) {\n    if (n < 0) return false;\n    if (n < 2) return true;\n    long x = n;\n    long y = (x + 1) / 2;\n    while (y < x) {\n        x = y;\n        y = (y + n / y) / 2;\n    }\n    return x * x == n;\n}\n
\n\n

El algoritmo converge muy rápido — en O(log log n) iteraciones. Para números hasta Long.MAX_VALUE, solo se necesitan 6-8 iteraciones.

\n\n

Ventajas: Precisión absoluta para todos los long (hasta 2^63-1). No usa double.

\n\n

Desventajas: La división es una operación costosa. Para números muy pequeños (n < 4), se puede agregar una verificación al inicio.

\n\n

Método 3: Búsqueda binaria de la raíz

\n\n

Otro algoritmo clásico: buscamos la raíz mediante búsqueda binaria en el intervalo [0, n]. Para long, el valor máximo de la raíz es 3 037 000 499 (sqrt(Long.MAX_VALUE)).

\n\n
public static boolean isPerfectSquareBinary(long n) {\n    if (n < 0) return false;\n    if (n < 2) return true;\n    long low = 1;\n    long high = 3037000499L; // sqrt(Long.MAX_VALUE)\n    while (low <= high) {\n        long mid = (low + high) >>> 1;\n        long square = mid * mid;\n        if (square == n) return true;\n        else if (square < n) low = mid + 1;\n        e                

Blogs

Book Recommendations