2008-12-05 25 views
60

Duplicar posibles:
Fastest way to determine if an integer's square root is an integer¿Qué es un buen algoritmo para determinar si una entrada es un cuadrado perfecto?

¿Qué es una manera de ver si un número es un perfect square?

bool IsPerfectSquare(long input) 
{ 
    // TODO 
} 

estoy usando C#, pero este es el lenguaje agnóstico.

Puntos de bonificación por claridad y simplicidad (esto no pretende ser código de golf).


Editar: Esto tiene mucho más complejo de lo que esperaba! Resulta que los problemas con la doble precisión se manifiestan de dos maneras. Primero, Math.Sqrt toma un doble que no puede aguantar mucho (gracias Jon).

En segundo lugar, la precisión de un doble perderá valores pequeños (.000 ... 00001) cuando tenga un cuadrado enorme, casi perfecto. Por ejemplo, mi implementación no pasó esta prueba para Math.Pow (10,18) +1 (la mía fue verdadera).

+0

También puedes buscar el método 'lsqrt' utilizado para la raíz cuadrada entera. – leppie

+0

Michael, Bill the Lizard hizo un buen punto que es solo una pregunta similar, no el duplicado exacto. No creo que la pregunta deba ser cerrada. Además, el problema del cuadrado perfecto es mucho más complejo en términos prácticos de lo que parece y las respuestas aquí hacen una gran contribución. –

+0

Para la solución que elijas, no olvides anteponer una comprobación rápida de la negatividad. – angus

Respuesta

98
bool IsPerfectSquare(long input) 
{ 
    long closestRoot = (long) Math.Sqrt(input); 
    return input == closestRoot * closestRoot; 
} 

Esto puede alejarse de algunos de los problemas de sólo la comprobación "es la raíz cuadrada de un número entero", pero posiblemente no todos. Potencialmente necesita para obtener un poco más funky:

bool IsPerfectSquare(long input) 
{ 
    double root = Math.Sqrt(input); 

    long rootBits = BitConverter.DoubleToInt64Bits(root); 
    long lowerBound = (long) BitConverter.Int64BitsToDouble(rootBits-1); 
    long upperBound = (long) BitConverter.Int64BitsToDouble(rootBits+1); 

    for (long candidate = lowerBound; candidate <= upperBound; candidate++) 
    { 
     if (candidate * candidate == input) 
     { 
      return true; 
     } 
    } 
    return false; 
} 

Icky, e innecesario para los que no sean muy grandes valores de cualquier cosa, pero creo que debe trabajo ...

+0

Parece que fuiste más rápido que yo ;-) Vaya, tu solución también es mejor, porque 'más cercano' es un nombre mucho más preciso. – Treb

+21

Me encanta el número de votaciones ascendentes que recibí * antes * de corregirlo a una solución más a prueba de balas;) –

+168

amigo, estás jon skeet. – Epaga

10
bool IsPerfectSquare(long input) 
{ 
    long SquareRoot = (long) Math.Sqrt(input); 
    return ((SquareRoot * SquareRoot) == input); 
} 
9

En Common Lisp, uso lo siguiente:

(defun perfect-square-p (n) 
    (= (expt (isqrt n) 2) 
    n)) 
+0

Heh. En http://stackoverflow.com/a/343862/31615, debo agregar que Common Lisp tiene una pila de números "completa", por lo que esto _solo funciona_ para cualquier número entero no negativo (limitado por la memoria de trabajo, por supuesto) . – Svante

+0

En SBCL, 'square' debe ser' expt': '(defun perfect-square-p (n) (= (expt (isqrt n) 2) n))'. – Ben

+0

@BenSima: en realidad, dado que 'square' no está definido en el estándar, debe definirlo (o sustituirlo) en cualquier implementación. Edito la respuesta para no tener esa dependencia. – Svante

Cuestiones relacionadas