Comprueba si un número es un cuadrado perfecto

Respuestas:

117

El problema de confiar en cualquier cálculo de punto flotante ( math.sqrt(x), o x**0.5) es que no puede estar realmente seguro de que sea exacto (para enteros suficientemente grandes x, no lo será, e incluso podría desbordarse). Afortunadamente (si no tiene prisa ;-) hay muchos enfoques de enteros puros, como los siguientes ...:

def is_square(apositiveint):
  x = apositiveint // 2
  seen = set([x])
  while x * x != apositiveint:
    x = (x + (apositiveint // x)) // 2
    if x in seen: return False
    seen.add(x)
  return True

for i in range(110, 130):
   print i, is_square(i)

Sugerencia: se basa en el "algoritmo babilónico" para la raíz cuadrada, consulte wikipedia . Se hace trabajo para cualquier número positivo para el que tenga suficiente memoria para el cálculo de proceder a la terminación ;-).

Editar : veamos un ejemplo ...

x = 12345678987654321234567 ** 2

for i in range(x, x+2):
   print i, is_square(i)

esto se imprime, como se desee (y también en un tiempo razonable ;-):

152415789666209426002111556165263283035677489 True
152415789666209426002111556165263283035677490 False

Por favor, antes de proponer soluciones basadas en flotante resultados intermedios de punto, asegurarse de que funcionan correctamente en este ejemplo simple - no es que duro (sólo tiene algunas verificaciones adicionales en caso de que la raíz cuadrada calculada es un poco apagado), sólo se necesita una un poco de cuidado.

Y luego prueba con x**7 y encuentre una forma inteligente de solucionar el problema que obtendrá,

OverflowError: long int too large to convert to float

tendrás que ser cada vez más inteligente a medida que los números sigan creciendo, por supuesto.

Si yo estaba en un apuro, por supuesto, que haría uso de gmpy - pero entonces, estoy claramente sesgado ;-).

>>> import gmpy
>>> gmpy.is_square(x**7)
1
>>> gmpy.is_square(x**7 + 1)
0

Sí, lo sé, eso es tan fácil que se siente como hacer trampa (un poco como me siento hacia Python en general ;-) - sin inteligencia en absoluto, solo franqueza y simplicidad perfectas (y, en el caso de gmpy, pura velocidad ; -) ...

Alex Martelli
fuente
Di lo que quieras sobre el autor, gmpy suena como una gran herramienta para esta tarea.
Mike Graham
3
El método babilónico funciona bien, pero necesita tener casos especiales para 0 y 1 para evitar la división por cero.
mpenkov
2
Por cierto, set([x])={x}
Oscar Mederos
6
¿No es el setexceso? ¿No es Babilónico simplemente converger int(sqrt(x)), donde solo tenemos que verificar si prev != next?
Tomasz Gandor
1
"Lo sé, es tan fácil que se siente como hacer trampa (un poco como me siento hacia Python en general".
Muy
38

Use el método de Newton para concentrarse rápidamente en la raíz cuadrada entera más cercana, luego eleve al cuadrado y vea si es su número. Ver isqrt .

Python ≥ 3.8 tiene math.isqrt. Si usa una versión anterior de Python, busque la def isqrt(n)implementación " " aquí .

import math

def is_square(i: int) -> bool:
    return i == math.isqrt(i) ** 2
Presidente James K. Polk
fuente
20

Dado que nunca puede depender de comparaciones exactas cuando se trata de cálculos de punto flotante (como estas formas de calcular la raíz cuadrada), una implementación menos propensa a errores sería

import math

def is_square(integer):
    root = math.sqrt(integer)
    return integer == int(root + 0.5) ** 2

Imagínese lo integeres 9. math.sqrt(9)podría ser 3.0, pero también podría ser algo como 2.99999o 3.00001, por lo que cuadrar el resultado de inmediato no es confiable. Sabiendo que se inttoma el valor mínimo, aumentar el valor flotante 0.5primero significa que obtendremos el valor que estamos buscando si estamos en un rango en el que floattodavía tiene una resolución lo suficientemente fina como para representar números cercanos al que estamos buscando. .

Mike Graham
fuente
5
Sería un poco mejor hacerlo if int(root + 0.5) ** 2 == integer:si intactúa en función floorde los números que nos interesan.
David Johnstone
@David Johnstone, cambié esta publicación para usar esa implementación, que estoy de acuerdo es mejor que la forma anterior que tenía. En cualquier caso, algunas de las otras técnicas que otros mencionan aquí son incluso mejores y más confiables.
Mike Graham
Entiendo que FP es aproximado, pero ¿ math.sqrt(9)realmente puede serlo alguna vez 2.99999? Python se floatasigna a C double, pero creo que incluso un tipo FP de 16 bits tiene más precisión que eso, así que tal vez si tuviera un compilador C que usara FP de 8 bits ("minifloats") como doubletipo Supongo que es técnicamente posible, pero me parece poco probable que ese sea el caso en cualquier computadora que ejecute Python en la actualidad.
Ken
@Ken, dije "algo como" para indicar que estaba llegando al concepto subyacente; no se garantiza que el valor que obtenga no sea un poco menor que el valor exacto. No puedo imaginar que math.sqrt(9)vuelva 2.99999en ningún sistema en particular, pero el resultado real depende del sistema y no se puede esperar que sea exacto.
Mike Graham
1
Esta función es incorrecta para un cuadrado grande como 152415789666209426002111556165263283035677489.
Acumenus
12

Si está interesado, tengo una respuesta puramente matemática a una pregunta similar en Math stackexchange, "Detectar cuadrados perfectos más rápido que extrayendo la raíz cuadrada" .

Mi propia implementación de isSquare (n) puede no ser la mejor, pero me gusta. Me tomó varios meses de estudio en teoría matemática, computación digital y programación de Python, comparándome con otros contribuyentes, etc., para realmente hacer clic con este método. Sin embargo, me gusta su simplicidad y eficiencia. No he visto mejor. Dime que piensas.

def isSquare(n):
    ## Trivial checks
    if type(n) != int:  ## integer
        return False
    if n < 0:      ## positivity
        return False
    if n == 0:      ## 0 pass
        return True

    ## Reduction by powers of 4 with bit-logic
    while n&3 == 0:    
        n=n>>2

    ## Simple bit-logic test. All perfect squares, in binary,
    ## end in 001, when powers of 4 are factored out.
    if n&7 != 1:
        return False

    if n==1:
        return True  ## is power of 4, or even power of 2


    ## Simple modulo equivalency test
    c = n%10
    if c in {3, 7}:
        return False  ## Not 1,4,5,6,9 in mod 10
    if n % 7 in {3, 5, 6}:
        return False  ## Not 1,2,4 mod 7
    if n % 9 in {2,3,5,6,8}:
        return False  
    if n % 13 in {2,5,6,7,8,11}:
        return False  

    ## Other patterns
    if c == 5:  ## if it ends in a 5
        if (n//10)%10 != 2:
            return False    ## then it must end in 25
        if (n//100)%10 not in {0,2,6}: 
            return False    ## and in 025, 225, or 625
        if (n//100)%10 == 6:
            if (n//1000)%10 not in {0,5}:
                return False    ## that is, 0625 or 5625
    else:
        if (n//10)%4 != 0:
            return False    ## (4k)*10 + (1,9)


    ## Babylonian Algorithm. Finding the integer square root.
    ## Root extraction.
    s = (len(str(n))-1) // 2
    x = (10**s) * 4

    A = {x, n}
    while x * x != n:
        x = (x + (n // x)) >> 1
        if x in A:
            return False
        A.add(x)
    return True

Muy claro. Primero verifica que tengamos un número entero, y además uno positivo. De lo contrario, no tiene sentido. Deja que 0 se deslice como Verdadero (necesario o el siguiente bloque es un bucle infinito).

El siguiente bloque de código elimina sistemáticamente las potencias de 4 en un subalgoritmo muy rápido que utiliza desplazamiento de bits y operaciones lógicas de bits. En última instancia, no estamos encontrando el isSquare de nuestro n original sino de un k <n que se ha reducido en potencias de 4, si es posible. Esto reduce el tamaño del número con el que estamos trabajando y realmente acelera el método babilónico, pero también hace que otras verificaciones también sean más rápidas.

El tercer bloque de código realiza una prueba lógica de bits booleana simple. Los tres dígitos menos significativos, en binario, de cualquier cuadrado perfecto son 001. Siempre. De todos modos, salvo los ceros iniciales resultantes de potencias de 4, que ya se han contabilizado. Si falla la prueba, inmediatamente sabrá que no es un cuadrado. Si pasa, no puede estar seguro.

Además, si terminamos con un 1 para un valor de prueba, entonces el número de prueba era originalmente una potencia de 4, incluido quizás el 1 mismo.

Al igual que el tercer bloque, el cuarto prueba el valor de un lugar en decimal usando un operador de módulo simple y tiende a capturar valores que se escapan de la prueba anterior. También una prueba de mod 7, mod 8, mod 9 y mod 13.

El quinto bloque de código comprueba algunos de los patrones cuadrados perfectos conocidos. Los números que terminan en 1 o 9 están precedidos por un múltiplo de cuatro. Y los números que terminan en 5 deben terminar en 5625, 0625, 225 o 025. Había incluido otros, pero me di cuenta de que eran redundantes o que nunca se usaron.

Por último, el sexto bloque de código se parece mucho a la respuesta del principal respondedor, Alex Martelli. Básicamente, encuentra la raíz cuadrada utilizando el antiguo algoritmo babilónico, pero restringiéndola a valores enteros ignorando el punto flotante. Realizado tanto para la velocidad como para ampliar las magnitudes de los valores que se pueden comprobar. Usé conjuntos en lugar de listas porque toma mucho menos tiempo, usé cambios de bits en lugar de división por dos, y elegí inteligentemente un valor de inicio inicial de manera mucho más eficiente.

Por cierto, probé el número de prueba recomendado por Alex Martelli, así como algunos números muchos órdenes de magnitud más grandes, como:

x=1000199838770766116385386300483414671297203029840113913153824086810909168246772838680374612768821282446322068401699727842499994541063844393713189701844134801239504543830737724442006577672181059194558045164589783791764790043104263404683317158624270845302200548606715007310112016456397357027095564872551184907513312382763025454118825703090010401842892088063527451562032322039937924274426211671442740679624285180817682659081248396873230975882215128049713559849427311798959652681930663843994067353808298002406164092996533923220683447265882968239141724624870704231013642255563984374257471112743917655991279898690480703935007493906644744151022265929975993911186879561257100479593516979735117799410600147341193819147290056586421994333004992422258618475766549646258761885662783430625 ** 2
for i in range(x, x+2):
    print(i, isSquare(i))

imprimió los siguientes resultados:

1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False

Y lo hizo en 0,33 segundos.

En mi opinión, mi algoritmo funciona igual que el de Alex Martelli, con todos los beneficios del mismo, pero tiene el beneficio agregado de rechazos de prueba simple altamente eficientes que ahorran mucho tiempo, sin mencionar la reducción en el tamaño de los números de prueba por potencias de 4, que mejora la velocidad, la eficiencia, la precisión y el tamaño de los números comprobables. Probablemente sea especialmente cierto en implementaciones que no son de Python.

Aproximadamente el 99% de todos los enteros se rechazan como no cuadrados antes de que se implemente la extracción de raíz babilónica, y en 2/3 del tiempo que le tomaría al babilónico rechazar el entero. Y aunque estas pruebas no aceleran el proceso de manera tan significativa, la reducción en todos los números de prueba a un valor impar al dividir todas las potencias de 4 realmente acelera la prueba de Babilonia.

Hice una prueba de comparación de tiempo. Probé todos los números enteros de 1 a 10 millones en sucesión. Usando solo el método babilónico por sí mismo (con mi suposición inicial especialmente diseñada), mi Surface 3 tomó un promedio de 165 segundos (con una precisión del 100%). Usando solo las pruebas lógicas en mi algoritmo (excluyendo el babilónico), tomó 127 segundos, rechazó el 99% de todos los enteros como no cuadrados sin rechazar por error ningún cuadrado perfecto. De los enteros que pasaron, solo el 3% fueron cuadrados perfectos (una densidad mucho mayor). Usando el algoritmo completo anterior que emplea tanto las pruebas lógicas como la extracción de la raíz babilónica, tenemos una precisión del 100% y la finalización de la prueba en solo 14 segundos. Los primeros 100 millones de enteros tardan aproximadamente 2 minutos y 45 segundos en probarse.

EDITAR: He podido reducir aún más el tiempo. Ahora puedo probar los enteros de 0 a 100 millones en 1 minuto y 40 segundos. Se pierde mucho tiempo comprobando el tipo de datos y la positividad. Eliminé los dos primeros controles y reduje el experimento un minuto. Se debe asumir que el usuario es lo suficientemente inteligente como para saber que los negativos y los flotantes no son cuadrados perfectos.

CogitoErgoCogitoSum
fuente
En cuanto a la simplicidad, es difícil superar la respuesta aceptada. En cuanto al rendimiento, el tuyo debería ser mejor. Soy escéptico sobre el valor de reducir el objetivo por potencias cuadradas de pequeños números primos, pero calcular símbolos jacobi para pequeños números primos debería ser una victoria. Y cuanto mayores sean los números, mayor será la ventaja de esta respuesta.
Presidente James K. Polk
1
La reducción por potencias de pequeños números primos es necesaria para que el cálculo del símbolo jacobi proporcione resultados deterministas. De lo contrario, es en el mejor de los casos probabilístico o determinista para la no cuadratura, pero no verifica la cuadratura. Es en parte por eso que factorizo ​​por potencias de cuadrados; los únicos símbolos jacobi que calculo son para los mismos primos pequeños que factorizo. También lo hago simplemente para reducir el tamaño del número de prueba para hacer que el método babilónico usado más tarde sea un poco más rápido (pero eso es discutible).
CogitoErgoCogitoSum
Bueno, ciertamente es una respuesta buena y única y si tengo algo de tiempo en el futuro, me gustaría jugar con esto, pruebe algunos tiempos variando el número de primos pequeños para ver si se puede encontrar un número óptimo en un tamaño de bits dado .
Presidente James K. Polk
Por supuesto, prueba mi código. Romperlo. No soy un programador de oficio, soy un estudiante de matemáticas. Python es solo un pasatiempo. Me gustaría saber si es más eficiente en promedio.
CogitoErgoCogitoSum
1
Si todavía está interesado, hay esencialmente una pregunta duplicada aquí con algunas respuestas interesantes, especialmente la respuesta de A.Rex .
Presidente James K. Polk
12
import math

def is_square(n):
    sqrt = math.sqrt(n)
    return (sqrt - int(sqrt)) == 0

Un cuadrado perfecto es un número que se puede expresar como el producto de dos números enteros iguales. math.sqrt(number)volver a float. int(math.sqrt(number))arroja el resultado a int.

Si la raíz cuadrada es un número entero, como 3, por ejemplo, entonces math.sqrt(number) - int(math.sqrt(number))será 0 y el ifenunciado será False. Si la raíz cuadrada era un número real como 3.2, entonces lo será Truee imprimirá "no es un cuadrado perfecto".

Falla para un gran no cuadrado como 152415789666209426002111556165263283035677490.

0xPwn
fuente
Cambio if (math.sqrt(number)-int(math.sqrt(number))):a a=math.sqrt(number)continuación, otra línea para: if a-int(a):. Esto se debe a que solo tiene que calcular la raíz cuadrada una vez, lo que en mi opinión para n grande es significativo
unseen_rider
@JamesKPolk ¿Por qué?
user1717828
Estoy bastante seguro de que sqrt - int (sqrt) es idéntico a sqrt% 1. Toda su función podría ser simplemente return math.sqrt (n)% 1 == 0
CogitoErgoCogitoSum
6

Mi respuesta es:

def is_square(x):
    return x**.5 % 1 == 0

Básicamente hace una raíz cuadrada, luego módulo por 1 para quitar la parte entera y si el resultado es 0, devuelve de lo Truecontrario False. En este caso, x puede ser cualquier número grande, pero no tan grande como el número flotante máximo que Python puede manejar: 1.7976931348623157e + 308

Es incorrecto para un no cuadrado grande como 152415789666209426002111556165263283035677490.

Lasagnenator
fuente
5

Esto se puede resolver usando el decimalmódulo para obtener raíces cuadradas de precisión arbitraria y verificaciones fáciles de "exactitud":

import math
from decimal import localcontext, Context, Inexact

def is_perfect_square(x):
    # If you want to allow negative squares, then set x = abs(x) instead
    if x < 0:
        return False

    # Create localized, default context so flags and traps unset
    with localcontext(Context()) as ctx:
        # Set a precision sufficient to represent x exactly; `x or 1` avoids
        # math domain error for log10 when x is 0
        ctx.prec = math.ceil(math.log10(x or 1)) + 1  # Wrap ceil call in int() on Py2
        # Compute integer square root; don't even store result, just setting flags
        ctx.sqrt(x).to_integral_exact()
        # If previous line couldn't represent square root as exact int, sets Inexact flag
        return not ctx.flags[Inexact]

Para demostraciones con valores realmente enormes:

# I just kept mashing the numpad for awhile :-)
>>> base = 100009991439393999999393939398348438492389402490289028439083249803434098349083490340934903498034098390834980349083490384903843908309390282930823940230932490340983098349032098324908324098339779438974879480379380439748093874970843479280329708324970832497804329783429874329873429870234987234978034297804329782349783249873249870234987034298703249780349783497832497823497823497803429780324
>>> sqr = base ** 2
>>> sqr ** 0.5  # Too large to use floating point math
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: int too large to convert to float

>>> is_perfect_power(sqr)
True
>>> is_perfect_power(sqr-1)
False
>>> is_perfect_power(sqr+1)
False

Si aumenta el tamaño del valor que se está probando, esto eventualmente se vuelve bastante lento (toma cerca de un segundo para un cuadrado de 200,000 bits), pero para números más moderados (digamos, 20,000 bits), aún es más rápido de lo que un humano notaría. valores individuales (~ 33 ms en mi máquina). Pero dado que la velocidad no era su principal preocupación, esta es una buena forma de hacerlo con las bibliotecas estándar de Python.

Por supuesto, sería mucho más rápido de usar gmpy2y simplemente probar gmpy2.mpz(x).is_square(), pero si los paquetes de terceros no son lo tuyo, lo anterior funciona bastante bien.

ShadowRanger
fuente
5

Acabo de publicar una ligera variación en algunos de los ejemplos anteriores en otro hilo ( Encontrar cuadrados perfectos ) y pensé que incluiría una ligera variación de lo que publiqué allí (usando nsqrt como variable temporal), en caso de que sea de interés / utilizar:

import math

def is_square(n):
  if not (isinstance(n, int) and (n >= 0)):
    return False 
  else:
    nsqrt = math.sqrt(n)
    return nsqrt == math.trunc(nsqrt)

Es incorrecto para un no cuadrado grande como 152415789666209426002111556165263283035677490.

listeza
fuente
2

Este es mi método:

def is_square(n) -> bool:
    return int(n**0.5)**2 == int(n)

Saca la raíz cuadrada del número. Convierta a entero. Toma la plaza. Si los números son iguales, entonces es un cuadrado perfecto de lo contrario no.

Es incorrecto para un cuadrado grande como 152415789666209426002111556165263283035677489.

Archu Sm
fuente
No funcionará para números negativos, pero sigue siendo una gran solución.
Rick M.
1

Puede realizar una búsqueda binaria de la raíz cuadrada redondeada. Cuadre el resultado para ver si coincide con el valor original.

Probablemente esté mejor con la respuesta de FogleBirds, aunque tenga cuidado, ya que la aritmética de punto flotante es aproximada, lo que puede desviar este enfoque. En principio, podría obtener un falso positivo de un entero grande que es uno más que un cuadrado perfecto, por ejemplo, debido a la pérdida de precisión.

Steve314
fuente
1

Si el módulo (resto) que sobra de dividir por la raíz cuadrada es 0, entonces es un cuadrado perfecto.

def is_square(num: int) -> bool:
    return num % math.sqrt(num) == 0

Verifiqué esto con una lista de cuadrados perfectos que iban hasta 1000.

GeneralCode
fuente
0
  1. Decide cuánto tiempo será el número.
  2. tomar un delta 0.000000000000 ....... 000001
  3. vea si (sqrt (x)) ^ 2 - x es mayor / igual / menor que delta y decida basándose en el error delta.
Cezar Alexandru Vancea
fuente
0

Esta respuesta no se refiere a su pregunta planteada, sino a una pregunta implícita que veo en el código que publicó, es decir, "¿cómo verificar si algo es un número entero?"

La primera respuesta que generalmente obtendrá a esa pregunta es "¡No lo haga!" Y es cierto que en Python, la verificación de tipos generalmente no es lo correcto.

Sin embargo, para esas raras excepciones, en lugar de buscar un punto decimal en la representación de cadena del número, lo que se debe hacer es usar la función isinstance :

>>> isinstance(5,int)
True
>>> isinstance(5.0,int)
False

Por supuesto, esto se aplica a la variable más que a un valor. Si quisiera determinar si el valor es un número entero, haría esto:

>>> x=5.0
>>> round(x) == x
True

Pero como todos los demás han cubierto en detalle, hay problemas de punto flotante que deben considerarse en la mayoría de los ejemplos de este tipo de cosas que no son juguetes.

Vicki Laidler
fuente
1
¿Qué significa "esto se aplica a la variable en lugar de a un valor"? Puede usar round (5.0) == 5.0 e isinstance (x, int) sin problemas. (Y el OOWTDI es solo para llamar a x.is_integer ().)
Veky
0

Si desea recorrer un rango y hacer algo para cada número que NO sea un cuadrado perfecto, puede hacer algo como esto:

def non_squares(upper):
    next_square = 0
    diff = 1
    for i in range(0, upper):
        if i == next_square:
            next_square += diff
            diff += 2
            continue
        yield i

Si desea hacer algo por cada número que ES un cuadrado perfecto, el generador es aún más fácil:

(n * n for n in range(upper))
Moberg
fuente
0

Creo que esto funciona y es muy simple:

import math

def is_square(num):
    sqrt = math.sqrt(num)
    return sqrt == int(sqrt)

Es incorrecto para un no cuadrado grande como 152415789666209426002111556165263283035677490.

alejandro izquierdo
fuente
Esto es lo mismo que la respuesta anterior.
Kowalski
0

Una variante de la solución de @Alex Martelli sin set

Cuando x in seenes True:

  • En la mayoría de los casos, es el último agregado, por ejemplo, 1022 produce la xsecuencia de 511, 256, 129, 68, 41, 32, 31 , 31 ;
  • En algunos casos (es decir, para los predecesores de cuadrados perfectos), es el penúltimo agregado, por ejemplo, 1023 produce 511, 256, 129, 68, 41, 32 , 31, 32 .

Por lo tanto, basta con detenerse en cuanto la corriente xsea ​​mayor o igual a la anterior:

def is_square(n):
    assert n > 1
    previous = n
    x = n // 2
    while x * x != n:
        x = (x + (n // x)) // 2
        if x >= previous:
            return False
        previous = x
    return True

x = 12345678987654321234567 ** 2
assert not is_square(x-1)
assert is_square(x)
assert not is_square(x+1)

Equivalencia con el algoritmo original probado para 1 <n <10 ** 7. En el mismo intervalo, esta variante ligeramente más simple es aproximadamente 1,4 veces más rápida.

Aristide
fuente
0
a=int(input('enter any number'))
flag=0
for i in range(1,a):
    if a==i*i:
        print(a,'is perfect square number')
        flag=1
        break
if flag==1:
    pass
else:
    print(a,'is not perfect square number')
Pemba Tamang
fuente
Aunque este código podría resolver el problema, una buena respuesta también debería explicar qué hace el código y cómo ayuda.
BDL
0

La idea es ejecutar un bucle desde i = 1 hasta el piso (sqrt (n)) y luego verificar si cuadrarlo hace n.

bool isPerfectSquare(int n) 
{ 
    for (int i = 1; i * i <= n; i++) { 

        // If (i * i = n) 
        if ((n % i == 0) && (n / i == i)) { 
            return true; 
        } 
    } 
    return false; 
} 
Pragati Verma
fuente
-3
import math

def is_square(n):
    sqrt = math.sqrt(n)
    return sqrt == int(sqrt)

Falla para un gran no cuadrado como 152415789666209426002111556165263283035677490.

Ravi Sankar Raju
fuente
2
Esta es una respuesta de solo código. Proporcione un poco de razonamiento.
hotzst
¿No puedes razonar a través de eso @hotzst? Tiene mucho sentido y ni siquiera soy un experto en Python. No es la mejor prueba, pero es válida tanto en teoría como para casos pequeños.
CogitoErgoCogitoSum
1
@CogitoErgoCogitoSum: No entiendes. Las búsquedas que utilizan motores de búsqueda como Google no encuentran respuestas de solo código. Si uno puede entender la respuesta es irrelevante.
Presidente James K. Polk