Verifique se um número é um quadrado perfeito

Respostas:

117

O problema de confiar em qualquer cálculo de ponto flutuante ( math.sqrt(x)ou x**0.5) é que você não pode realmente ter certeza de que é exato (para números inteiros suficientemente grandes x, não será e pode até mesmo estourar). Felizmente (se não houver pressa ;-), existem muitas abordagens de inteiros puros, como as seguintes ...:

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)

Dica: é baseado no "algoritmo babilônico" para raiz quadrada, consulte a wikipedia . Ele faz o trabalho para qualquer número positivo para o qual você tem memória suficiente para a computação para avançar para a conclusão ;-).

Edit : vamos ver um exemplo ...

x = 12345678987654321234567 ** 2

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

isso é impresso, conforme desejado (e em um período de tempo razoável também ;-):

152415789666209426002111556165263283035677489 True
152415789666209426002111556165263283035677490 False

Por favor, antes de propor soluções baseadas em resultados intermediários de ponto flutuante, certifique-se eles funcionam corretamente neste exemplo simples - não é que difícil (você só precisa de algumas verificações extras no caso do sqrt computadorizada é um pouco fora), só tem um pouco de cuidado.

Em seguida, tente x**7encontrar uma maneira inteligente de contornar o problema que você terá,

OverflowError: long int too large to convert to float

você terá que ficar cada vez mais inteligente à medida que os números continuam crescendo, é claro.

Se eu estivesse com pressa, é claro, usaria o gmpy - mas sou claramente tendencioso ;-).

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

Sim, eu sei, isso é tão fácil que parece que estou trapaceando (um pouco como eu me sinto em relação ao Python em geral ;-) - nenhuma inteligência, apenas franqueza e simplicidade perfeitas (e, no caso do gmpy, velocidade absoluta ; -) ...

Alex Martelli
fonte
Diga o que quiser sobre o autor. O gmpy parece uma ótima ferramenta para essa tarefa.
Mike Graham,
3
O método babilônico funciona bem, mas você precisa ter casos especiais para 0 e 1 para evitar a divisão por zero.
mpenkov
2
A propósito, set([x])={x}
Oscar Mederos
6
Não é o setovekill? Babylonian não converge para int(sqrt(x)), onde nós apenas temos que verificar se prev != next?
Tomasz Gandor
1
"Eu sei, isso é tão fácil que parece que estou trapaceando (um pouco como eu me sinto em relação ao Python em geral". É verdade;)
Arulx Z
39

Use o método de Newton para zerar rapidamente a raiz quadrada inteira mais próxima, depois eleve ao quadrado e veja se é o seu número. Veja isqrt .

Python ≥ 3,8 tem math.isqrt. Se estiver usando uma versão mais antiga do Python, procure a def isqrt(n)implementação " " aqui .

import math

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

Visto que você nunca pode depender de comparações exatas ao lidar com cálculos de ponto flutuante (como essas formas de calcular a raiz quadrada), uma implementação menos sujeita a erros seria

import math

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

Imagine integeré 9. math.sqrt(9)poderia ser 3.0, mas também poderia ser algo como 2.99999ou 3.00001, portanto, ajustar o resultado de imediato não é confiável. Sabendo que intleva o valor mínimo, aumentar o valor flutuante 0.5primeiro significa que obteremos o valor que estamos procurando se estivermos em um intervalo em que floatainda tenha uma resolução fina o suficiente para representar números próximos ao que estamos procurando .

Mike Graham
fonte
5
Seria um pouco melhor apenas fazer o if int(root + 0.5) ** 2 == integer:if intage como floorpara os números que nos interessam.
David Johnstone
@David Johnstone, mudei este post para usar essa implementação, que concordo que é mais legal do que antes. Em qualquer caso, algumas das outras técnicas que outros mencionam aqui são ainda melhores e mais confiáveis.
Mike Graham
Eu entendo que FP é aproximado, mas pode math.sqrt(9)realmente ser 2.99999? Python's floatmapeia para C's double, mas acho que mesmo um tipo de FP de 16 bits tem mais precisão do que isso, talvez se você tivesse um compilador C que usasse FP de 8 bits ("minifloats") como seu doubletipo? Suponho que seja tecnicamente possível, mas me parece improvável que seja o caso em qualquer computador que execute Python hoje.
Ken
@Ken, eu disse "algo como" para indicar que estava chegando ao conceito subjacente; não é garantido que o valor obtido não seja um pouco menor que o valor exato. Não posso imaginar que math.sqrt(9)isso aconteça 2.99999em qualquer sistema específico, mas o resultado real depende do sistema e não pode ser esperado que seja exato.
Mike Graham
1
Esta função está incorreta para um grande quadrado, como 152415789666209426002111556165263283035677489.
Acumenus
12

Se você estiver interessado, eu tenho uma resposta de matemática pura para uma pergunta semelhante na troca de pilha de matemática, "Detectando quadrados perfeitos mais rápido do que extraindo a raiz quadrada" .

Minha própria implementação de isSquare (n) pode não ser a melhor, mas eu gosto. Levei vários meses de estudo em teoria matemática, computação digital e programação python, comparando-me com outros colaboradores, etc., para realmente clicar com este método. Eu gosto de sua simplicidade e eficiência. Eu não vi melhor. Me diga o que você acha.

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

Bem direto. Primeiro, ele verifica se temos um número inteiro e positivo. Caso contrário, não há nenhum ponto. Ele deixa 0 passar por True (necessário ou então o próximo bloco é um loop infinito).

O próximo bloco de código remove sistematicamente potências de 4 em um sub-algoritmo muito rápido usando operações de bit shift e lógica de bit. No final das contas, não estamos encontrando o isSquare de nosso n original, mas de um k <n que foi reduzido em potências de 4, se possível. Isso reduz o tamanho do número com o qual estamos trabalhando e realmente acelera o método babilônico, mas também torna outras verificações mais rápidas.

O terceiro bloco de código executa um teste simples de lógica de bits booleana. Os três dígitos menos significativos, em binário, de qualquer quadrado perfeito são 001. Sempre. Exceto pelos zeros à esquerda resultantes de potências de 4, de qualquer maneira, que já foram contabilizados. Se falhar no teste, você saberá imediatamente que não é um quadrado. Se passar, você não pode ter certeza.

Além disso, se terminarmos com 1 para um valor de teste, o número do teste seria originalmente uma potência de 4, incluindo talvez o próprio 1.

Como o terceiro bloco, o quarto testa o valor de uma casa em decimal usando o operador de módulo simples e tende a capturar valores que escapam ao teste anterior. Também um teste de mod 7, mod 8, mod 9 e mod 13.

O quinto bloco de código verifica alguns dos padrões de quadrados perfeitos bem conhecidos. Os números que terminam em 1 ou 9 são precedidos por um múltiplo de quatro. E os números que terminam em 5 devem terminar em 5625, 0625, 225 ou 025. Eu havia incluído outros, mas percebi que eram redundantes ou nunca foram realmente usados.

Por fim, o sexto bloco de código se parece muito com o que respondeu com maior frequência - Alex Martelli - a resposta. Basicamente encontra a raiz quadrada usando o antigo algoritmo babilônico, mas restringindo-a a valores inteiros enquanto ignora o ponto flutuante. Feito para velocidade e extensão das magnitudes dos valores que são testáveis. Usei conjuntos em vez de listas porque leva muito menos tempo, usei deslocamentos de bits em vez de divisão por dois e escolhi inteligentemente um valor inicial de início com muito mais eficiência.

A propósito, testei o número de teste recomendado por Alex Martelli, bem como alguns números com magnitude de ordens maiores, como:

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

imprimiu os seguintes resultados:

1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False

E fez isso em 0,33 segundos.

Em minha opinião, meu algoritmo funciona da mesma forma que o de Alex Martelli, com todos os benefícios, mas tem o benefício adicional de rejeições de teste simples altamente eficientes que economizam muito tempo, sem mencionar a redução no tamanho dos números de teste por potências de 4, que melhora a velocidade, eficiência, precisão e o tamanho dos números que podem ser testados. Provavelmente, especialmente verdadeiro em implementações não Python.

Aproximadamente 99% de todos os inteiros são rejeitados como não-Quadrados antes mesmo de a extração da raiz da Babilônia ser implementada, e em 2/3 do tempo que o Babylonian levaria para rejeitar o inteiro. E embora esses testes não acelerem o processo significativamente, a redução em todos os números de teste para ímpar dividindo todas as potências de 4, na verdade acelera o teste babilônico.

Eu fiz um teste de comparação de tempo. Testei todos os inteiros de 1 a 10 milhões em sucessão. Usando apenas o método babilônico por si só (com meu palpite inicial especialmente adaptado), meu Surface 3 levou uma média de 165 segundos (com 100% de precisão). Usando apenas os testes lógicos em meu algoritmo (excluindo o Babylonian), levou 127 segundos, ele rejeitou 99% de todos os inteiros como não-quadrados sem rejeitar por engano quaisquer quadrados perfeitos. Desses inteiros aprovados, apenas 3% eram quadrados perfeitos (uma densidade muito maior). Usando o algoritmo completo acima, que emprega os testes lógicos e a extração de raiz da Babilônia, temos 100% de precisão e conclusão do teste em apenas 14 segundos. Os primeiros 100 milhões de números inteiros levam cerca de 2 minutos e 45 segundos para serem testados.

EDIT: Consegui reduzir ainda mais o tempo. Agora posso testar os inteiros de 0 a 100 milhões em 1 minuto e 40 segundos. Muito tempo é perdido verificando o tipo de dados e a positividade. Elimine as duas primeiras verificações e reduzo o experimento por um minuto. É preciso presumir que o usuário é inteligente o suficiente para saber que negativos e flutuantes não são quadrados perfeitos.

CogitoErgoCogitoSum
fonte
Quanto à simplicidade, é difícil superar a resposta aceita. Em termos de desempenho, o seu deve ser melhor. Eu sou cético quanto ao valor de reduzir o alvo por potências quadradas de pequenos primos, mas computar símbolos jacobi para pequenos primos deve ser uma vitória. E quanto maiores os números, maior a vantagem dessa resposta.
Presidente James K. Polk
1
A redução por potências de pequenos primos é necessária para que o cálculo do símbolo jacobi forneça resultados determinísticos. Caso contrário, é, na melhor das hipóteses, probabilístico ou determinístico para não quadratura, mas não verifica quadratura. É parcialmente por isso que faço fatoração por potências dos quadrados; os únicos símbolos jacobi que calculo são para os mesmos pequenos primos que fatoro. Eu também faço isso simplesmente para reduzir o tamanho do número de teste para tornar o método babilônico usado posteriormente um pouco mais rápido (mas isso é discutível).
CogitoErgoCogitoSum
Bem, é certamente uma resposta boa e única e, se eu tiver algum tempo no futuro, gostaria de brincar com isso, tente alguns intervalos variando o número de pequenos primos para ver se um número ideal pode ser encontrado em um determinado tamanho de bits .
Presidente James K. Polk de
Por suposto, teste meu código. Quebre isso. Não sou um programador de profissão, sou um graduado em matemática. Python é apenas um hobby. Eu ficaria curioso se é mais eficiente em média.
CogitoErgoCogitoSum
1
Se você ainda estiver interessado em, há essencialmente uma pergunta duplicada aqui com algumas respostas interessantes, especialmente a resposta de A.Rex .
Presidente James K. Polk
12
import math

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

Um quadrado perfeito é um número que pode ser expresso como o produto de dois inteiros iguais. math.sqrt(number)retornar a float. int(math.sqrt(number))lança o resultado para int.

Se a raiz quadrada for um número inteiro, como 3, por exemplo, então math.sqrt(number) - int(math.sqrt(number))será 0, e a ifdeclaração será False. Se a raiz quadrada for um número real como 3,2, então será Truee imprimirá "não é um quadrado perfeito".

Ele falha para um grande não quadrado, como 152415789666209426002111556165263283035677490.

0xPwn
fonte
Mudar if (math.sqrt(number)-int(math.sqrt(number))):para a=math.sqrt(number), em seguida, uma outra linha para: if a-int(a):. Isso ocorre porque ele só precisa calcular a raiz quadrada uma vez, o que imo para n grande é significativo
unseen_rider
@JamesKPolk Por que isso?
user1717828
Tenho certeza que sqrt - int (sqrt) é idêntico a sqrt% 1. Sua função inteira poderia retornar math.sqrt (n)% 1 == 0
CogitoErgoCogitoSum
6

Minha resposta é:

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

Ele basicamente faz uma raiz quadrada, então o módulo por 1 para retirar a parte inteira e se o resultado for 0 retornar, Truecaso contrário, retornar False. Nesse caso, x pode ser qualquer número grande, mas não tão grande quanto o número flutuante máximo que o python pode manipular: 1.7976931348623157e + 308

É incorreto para um grande não quadrado, como 152415789666209426002111556165263283035677490.

Lasagnenator
fonte
5

Isso pode ser resolvido usando o decimalmódulo para obter raízes quadradas de precisão arbitrária e verificações fáceis de "exatidão":

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 demonstração com valores verdadeiramente 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

Se você aumentar o tamanho do valor que está sendo testado, isso eventualmente se torna bastante lento (leva quase um segundo para um quadrado de 200.000 bits), mas para números mais moderados (digamos, 20.000 bits), ainda é mais rápido do que um humano notaria. valores individuais (~ 33 ms na minha máquina). Mas como a velocidade não era sua principal preocupação, essa é uma boa maneira de fazer isso com as bibliotecas padrão do Python.

Claro, seria muito mais rápido usar gmpy2e apenas testar gmpy2.mpz(x).is_square(), mas se você não gosta de pacotes de terceiros , o procedimento acima funciona muito bem.

ShadowRanger
fonte
5

Acabei de postar uma pequena variação em alguns dos exemplos acima em outro tópico ( Encontrando quadrados perfeitos ) e pensei em incluir uma pequena variação do que postei aqui (usando nsqrt como uma variável temporária), caso seja de interesse / usar:

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)

É incorreto para um grande não quadrado, como 152415789666209426002111556165263283035677490.

coragem
fonte
2

Este é o meu método:

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

Tire a raiz quadrada do número. Converta para inteiro. Pegue a praça. Se os números forem iguais, então é um quadrado perfeito, caso contrário, não.

É incorreto para um grande quadrado, como 152415789666209426002111556165263283035677489.

Archu Sm
fonte
Não vai funcionar para números negativos, mas ainda é uma ótima solução!
Rick M.
1

Você poderia fazer uma busca binária pela raiz quadrada arredondada. Quadrado o resultado para ver se ele corresponde ao valor original.

Você provavelmente está melhor com a resposta de FogleBirds - mas cuidado, pois a aritmética de ponto flutuante é aproximada, o que pode atrapalhar essa abordagem. Você poderia, em princípio, obter um falso positivo de um inteiro grande que é mais um do que um quadrado perfeito, por exemplo, devido à perda de precisão.

Steve314
fonte
1

Se o módulo (resto) restante da divisão pela raiz quadrada for 0, então é um quadrado perfeito.

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

Eu verifiquei isso em uma lista de quadrados perfeitos que chegava a 1000.

GeneralCode
fonte
0
  1. Decida quanto tempo o número será.
  2. pegue um delta 0,000000000000 ....... 000001
  3. veja se (sqrt (x)) ^ 2 - x é maior / igual / menor que delta e decida com base no erro delta.
Cezar Alexandru Vancea
fonte
0

Esta resposta não pertence à sua pergunta declarada, mas a uma pergunta implícita que vejo no código que você postou, ou seja, "como verificar se algo é um número inteiro?"

A primeira resposta que você geralmente obterá a essa pergunta é "Não!" E é verdade que em Python, a verificação de tipos geralmente não é a coisa certa a se fazer.

Para essas raras exceções, no entanto, em vez de procurar um ponto decimal na representação da string do número, a coisa a fazer é usar a função isinstance :

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

Claro que isso se aplica à variável e não a um valor. Se eu quisesse determinar se o valor é um número inteiro, faria o seguinte:

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

Mas, como todo mundo cobriu em detalhes, há questões de ponto flutuante a serem consideradas na maioria dos exemplos que não são brinquedos desse tipo de coisa.

Vicki Laidler
fonte
1
O que significa "isto se aplica à variável e não a um valor"? Você pode usar round (5.0) == 5.0 e isinstance (x, int) sem problemas. (E o OOWTDI é apenas para chamar x.is_integer ().)
Veky
0

Se quiser fazer um loop em um intervalo e fazer algo para cada número que NÃO seja um quadrado perfeito, você pode fazer algo assim:

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

Se você quiser fazer algo para cada número que seja um quadrado perfeito, o gerador é ainda mais fácil:

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

Acho que funciona e é muito simples:

import math

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

É incorreto para um grande não quadrado, como 152415789666209426002111556165263283035677490.

alejandro izquierdo
fonte
Esta é a mesma resposta acima.
Ekrem Dinçel
0

Uma variante da solução @Alex Martelli sem set

Quando x in seené True:

  • Na maioria dos casos, é o último adicionado, por exemplo, 1022 produz a xsequência de 511, 256, 129, 68, 41, 32, 31 , 31 ;
  • Em alguns casos (ou seja, para os predecessores de quadrados perfeitos), é o penúltimo adicionado, por exemplo, 1023 produz 511, 256, 129, 68, 41, 32 , 31, 32 .

Portanto, basta parar assim que a corrente xfor maior ou igual à 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)

Equivalência com o algoritmo original testado para 1 <n <10 ** 7. No mesmo intervalo, esta variante ligeiramente mais simples é cerca de 1,4 vezes mais rápida.

Aristide
fonte
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
fonte
Embora esse código possa resolver o problema, uma boa resposta também deve explicar o que o código faz e como isso ajuda.
BDL de
0

A ideia é executar um loop de i = 1 até floor (sqrt (n)) e verificar se ao quadrado resulta 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
fonte
-2
import math

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

Ele falha para um grande não quadrado, como 152415789666209426002111556165263283035677490.

Ravi Sankar Raju
fonte
2
Esta é uma resposta apenas em código. Forneça um pouco de raciocínio.
hotzst
Você não consegue raciocinar através desse @hotzst? Faz todo o sentido e nem sou um especialista em python. Não é o melhor teste, mas é válido tanto em teoria quanto para pequenos casos.
CogitoErgoCogitoSum
1
@CogitoErgoCogitoSum: Você não entende. Respostas somente de código não são encontradas por pesquisas usando mecanismos de pesquisa como o Google. Se alguém pode entender a resposta é irrelevante.
Presidente James K. Polk