Bir sayının tam kare olup olmadığını nasıl kontrol edebilirim?
Hız, şimdilik sadece çalışıyor.
Yanıtlar:
Herhangi bir kayan nokta hesaplamasına ( math.sqrt(x)
veya x**0.5
) güvenmenin sorunu, tam olduğundan emin olamamanızdır (yeterince büyük tamsayılar için x
, olmayacak ve hatta taşabilir). Neyse ki (aceleniz yoksa ;-) aşağıdakiler gibi birçok saf tam sayı yaklaşımı vardır ...:
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)
İpucu: Karekök için "Babil algoritmasına" dayalıdır, bkz. Wikipedia . Bu does sen ;-) hesaplama tamamlanmasına yönelik yeterli belleğe sahip olduğu herhangi bir pozitif sayının işi.
Düzenleme : bir örnek görelim ...
x = 12345678987654321234567 ** 2
for i in range(x, x+2):
print i, is_square(i)
bu, istenildiği gibi (ve makul bir sürede de ;-) yazdırılır:
152415789666209426002111556165263283035677489 True
152415789666209426002111556165263283035677490 False
Lütfen, kayan noktalı ara sonuçlara dayalı çözümler önermeden önce, bu basit örnek üzerinde doğru çalıştıklarından emin olun - bu o kadar da zor değil (hesaplanan sqrt'nin biraz azalması durumunda sadece birkaç ekstra kontrole ihtiyacınız var), sadece biraz özen.
Sonra deneyip karşılaşacağınız x**7
sorunu çözmek için akıllıca bir yol bulun,
OverflowError: long int too large to convert to float
Elbette sayılar arttıkça daha da akıllı olmanız gerekecek.
Ben ise oldu acele, tabii ki, ben kullanırım gmpy ;-) ama sonra, açıkça önyargılı değilim -.
>>> import gmpy
>>> gmpy.is_square(x**7)
1
>>> gmpy.is_square(x**7 + 1)
0
Evet, biliyorum, bu çok kolay, hile yapmak gibi hissettiriyor (genel olarak Python'a karşı hissettiklerim biraz ;-) - hiç zeka yok, sadece mükemmel doğruluk ve basitlik (ve, gmpy durumunda, tam hız ; -) ...
set([x])
={x}
set
Ovekill değil mi? Babil int(sqrt(x))
, kontrol etmemiz gereken yere yaklaşmıyor prev != next
mu?
En yakın tam sayı karekökünü hızla sıfırlamak için Newton'un yöntemini kullanın, ardından karesini alın ve sizin sayınız olup olmadığına bakın. İsqrt bakın .
Python ≥ 3.8 vardır math.isqrt
. Python'un daha eski bir sürümünü kullanıyorsanız, burada " def isqrt(n)
" uygulamasını arayın .
import math
def is_square(i: int) -> bool:
return i == math.isqrt(i) ** 2
Kayan nokta hesaplamalarıyla uğraşırken asla kesin karşılaştırmalara güvenemeyeceğiniz için (karekök hesaplamanın bu yolları gibi), daha az hataya açık bir uygulama olacaktır.
import math
def is_square(integer):
root = math.sqrt(integer)
return integer == int(root + 0.5) ** 2
Imagine integer
IS 9
. math.sqrt(9)
olabilir 3.0
, ancak aynı zamanda 2.99999
veya gibi bir şey de olabilir 3.00001
, bu nedenle sonucun hemen karesini almak güvenilir değildir. Bunun int
taban değerini aldığını bilmek, 0.5
ilk önce kayan değeri artırmak, aradığımız float
sayıya yakın sayıları temsil etmek için hala yeterince iyi bir çözünürlüğe sahip bir aralıkta isek, aradığımız değeri elde edeceğimiz anlamına gelir. .
if int(root + 0.5) ** 2 == integer:
sanki int
gibi davranır floor
numaralar için biz önemsiyoruz.
math.sqrt(9)
gerçekten olabilir 2.99999
mi? Python'un float
C'ler için harita double
, ama ben bile 16 bit FP tipi yani belki onun kadar 8 bit FP ( "minifloats") kullanılan bir C derleyicisi olsaydı, bundan daha fazla hassasiyete sahiptir düşünüyorum double
tip? Sanırım teknik olarak mümkün, ancak bugün Python çalıştıran herhangi bir bilgisayarda durumun böyle olması bana pek olası görünmüyor.
math.sqrt(9)
döneceğini hayal edemiyorum 2.99999
, ancak gerçek sonuç sisteme bağlıdır ve kesin olması beklenemez.
Eğer ilgilenirseniz, matematiksel yığın değişiminde benzer bir soruya saf matematik cevabım var: "Mükemmel kareleri karekök çıkarmaktan daha hızlı tespit etmek" .
Kendi isSquare (n) uygulamam en iyisi olmayabilir, ama hoşuma gitti. Matematik teorisi, dijital hesaplama ve python programlama üzerine birkaç ay çalıştım, kendimi diğer katkıda bulunanlarla karşılaştırdım, vb. Bu yöntemi gerçekten tıkladım. Yine de sadeliğini ve verimliliğini seviyorum. Daha iyisini görmedim. Bana ne düşündüğünü söyle.
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
Oldukça yalındır. Önce bir tamsayımız olup olmadığını kontrol eder ve bunda pozitif bir tane. Aksi takdirde hiçbir anlamı yok. 0'ın True olarak kaymasına izin verir (gerekli veya bir sonraki blok sonsuz döngüdür).
Bir sonraki kod bloğu, bit kaydırma ve bit mantık işlemlerini kullanarak çok hızlı bir alt algoritmada 4'ün gücünü sistematik olarak kaldırır. Nihayetinde, orijinal n'mizin isSquare'ini değil, mümkünse 4'ün katları ile küçültülmüş bir k <n'yi buluyoruz. Bu, üzerinde çalıştığımız sayının boyutunu küçültür ve Babil yöntemini gerçekten hızlandırır, ancak diğer kontrolleri de daha hızlı hale getirir.
Üçüncü kod bloğu, basit bir Boole bit-mantık testi gerçekleştirir. Herhangi bir tam karenin ikili olarak en az anlamlı üç rakamı 001'dir. Her zaman. Zaten hesaba katılmış olan 4'ün üslerinden kaynaklanan baştaki sıfırlar için tasarruf edin. Testi geçemezse, bunun bir kare olmadığını hemen anlarsınız. Geçerse emin olamazsın.
Ayrıca, bir test değeri için 1 elde edersek, test numarası başlangıçta 4'ün üssüydü, belki de 1'in kendisi de dahil.
Üçüncü blok gibi, dördüncü blok da bir basamaklı değeri basit modül işleci kullanarak ondalık olarak test eder ve önceki testte kayan değerleri yakalama eğilimindedir. Ayrıca bir mod 7, mod 8, mod 9 ve mod 13 testi.
Beşinci kod bloğu, iyi bilinen bazı mükemmel kare desenlerini kontrol eder. 1 veya 9 ile biten sayıların önünde dörtten bir kat bulunur. Ve 5 ile biten sayılar 5625, 0625, 225 veya 025 ile bitmelidir. Başkalarını da dahil ettim ama bunların gereksiz olduğunu veya hiç kullanılmadığını fark ettim.
Son olarak, altıncı kod bloğu en çok cevaplayan kişinin - Alex Martelli'nin - cevabına çok benziyor. Temelde eski Babil algoritmasını kullanarak karekökü bulur, ancak kayan noktayı göz ardı ederken tam sayı değerleriyle sınırlar. Hem hız hem de test edilebilir değerlerin büyüklüklerini genişletmek için yapılır. Liste yerine kümeler kullandım çünkü çok daha az zaman alıyor, ikiye bölmek yerine bit kaydırma kullandım ve akıllıca bir başlangıç başlangıç değerini çok daha verimli seçtim.
Bu arada, Alex Martelli'nin tavsiye ettiği test numarasının yanı sıra, birkaç numara, birçok büyüklükten daha büyük siparişleri test ettim, örneğin:
x=1000199838770766116385386300483414671297203029840113913153824086810909168246772838680374612768821282446322068401699727842499994541063844393713189701844134801239504543830737724442006577672181059194558045164589783791764790043104263404683317158624270845302200548606715007310112016456397357027095564872551184907513312382763025454118825703090010401842892088063527451562032322039937924274426211671442740679624285180817682659081248396873230975882215128049713559849427311798959652681930663843994067353808298002406164092996533923220683447265882968239141724624870704231013642255563984374257471112743917655991279898690480703935007493906644744151022265929975993911186879561257100479593516979735117799410600147341193819147290056586421994333004992422258618475766549646258761885662783430625 ** 2
for i in range(x, x+2):
print(i, isSquare(i))
aşağıdaki sonuçları yazdırdı:
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False
Ve bunu 0.33 saniyede yaptı.
Benim fikrime göre, benim algoritmam Alex Martelli'nin tüm faydalarıyla aynı şekilde çalışıyor, ancak çok fazla zaman kazandıran yüksek verimli basit test redlerinin ek faydasına sahip, test sayılarının boyutunun güçlerine göre azalmasından bahsetmiyorum bile 4, hız, verimlilik, doğruluk ve test edilebilir sayıların boyutunu geliştirir. Muhtemelen özellikle Python dışı uygulamalarda doğrudur.
Tam sayıların kabaca% 99'u, Babil kökü çıkarma işlemi uygulanmadan önce Kare dışı olarak reddedilir ve 2 / 3'te Babil'in tamsayıyı reddetmesi gerekir. Ve bu testler süreci önemli ölçüde hızlandırmasa da, tüm test sayılarının 4'ün tüm güçlerini bölerek teke indirilmesi Babil testini gerçekten hızlandırır.
Bir zaman karşılaştırma testi yaptım. Arka arkaya 1'den 10 Milyon'a kadar tüm tam sayıları test ettim. Yalnızca Babil yöntemini kullanarak (benim özel olarak uyarlanmış ilk tahminimle) Surface 3'üm ortalama 165 saniye (% 100 doğrulukla) aldı. Algoritmamdaki mantıksal testleri kullanarak (Babil hariç) 127 saniye sürdü, tüm tamsayıların% 99'unu Kare dışı olarak reddetti ve herhangi bir mükemmel kareyi yanlışlıkla reddetti. Geçen tam sayılardan sadece% 3'ü mükemmel Karelerdi (çok daha yüksek yoğunluk). Hem mantıksal testleri hem de Babil kökü çıkarımını kullanan yukarıdaki algoritmanın tamamını kullanarak,% 100 doğruluk elde ediyoruz ve testi yalnızca 14 saniyede tamamlıyoruz. İlk 100 Milyon tamsayının sınanması kabaca 2 dakika 45 saniye sürer.
DÜZENLEME: Zamanı daha da kısalttım. Artık 0 ila 100 Milyon tam sayıları 1 dakika 40 saniyede test edebilirim. Veri türünü ve pozitifliğini kontrol etmek için çok zaman harcanıyor. İlk iki kontrolü eleyin ve deneyi bir dakika kısaltırım. Kullanıcının, negatiflerin ve kayan değerlerin mükemmel kareler olmadığını bilecek kadar akıllı olduğu varsayılmalıdır.
import math
def is_square(n):
sqrt = math.sqrt(n)
return (sqrt - int(sqrt)) == 0
Tam kare, iki eşit tam sayının çarpımı olarak ifade edilebilen bir sayıdır. math.sqrt(number)
dönüş a float
. int(math.sqrt(number))
sonucu yayınlar int
.
Karekök, örneğin 3 gibi bir tamsayı ise, o math.sqrt(number) - int(math.sqrt(number))
zaman 0 olacak ve if
ifade olacaktır False
. Eğer karekök 3.2 gibi gerçek bir sayı ise, o zaman olacak True
ve "bu tam bir kare değil" yazacaktır.
152415789666209426002111556165263283035677490 gibi büyük kare olmayan için başarısız olur .
if (math.sqrt(number)-int(math.sqrt(number))):
için a=math.sqrt(number)
daha sonra başka bir satır: if a-int(a):
. Bunun nedeni, karekökü yalnızca bir kez hesaplaması gerektiğidir, bu büyük n için imo önemlidir
Cevabım:
def is_square(x):
return x**.5 % 1 == 0
Temelde bir karekök yapar, ardından tamsayı kısmını ayırmak için 1 ile modulo yapar ve sonuç 0 ise, True
aksi takdirde geri döner False
. Bu durumda x herhangi bir büyük sayı olabilir, ancak python'un kaldırabileceği maksimum kayan sayı kadar büyük olmayabilir: 1.7976931348623157e + 308
152415789666209426002111556165263283035677490 gibi büyük kare olmayanlar için yanlıştır .
Bu kullanılarak çözülebilir modülü keyfi hassas karekök ve "doğruluk" için kolay kontrolleri almak için:decimal
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]
Gerçekten büyük değerlere sahip gösteri için:
# 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
Test edilen değerin boyutunu artırırsanız, bu sonunda oldukça yavaşlar (200.000 bitlik bir kare için bir saniyeye yakın sürer), ancak daha makul sayılar için (örneğin 20.000 bit), yine de bir insanın fark edeceğinden daha hızlıdır. bireysel değerler (makinemde ~ 33 ms). Ancak hız birincil endişeniz olmadığı için, bu, Python'un standart kitaplıklarıyla bunu yapmanın iyi bir yoludur.
Tabii ki, kullanmak gmpy2
ve sadece test etmek çok daha hızlı olurdu gmpy2.mpz(x).is_square()
, ancak üçüncü parti paketler size göre değilse, yukarıdakiler oldukça iyi çalışıyor.
Başka bir iş parçacığı üzerinde yukarıdaki örneklerden bazılarının küçük bir varyasyonunu yayınladım ( Mükemmel kareler bulma ) ve burada yayınladığım şeyin küçük bir varyasyonunu dahil edeceğimi düşündüm (geçici bir değişken olarak nsqrt kullanarak), eğer ilgi çekiyorsa / kullanım:
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)
152415789666209426002111556165263283035677490 gibi büyük kare olmayanlar için yanlıştır .
Bu benim yöntemim:
def is_square(n) -> bool:
return int(n**0.5)**2 == int(n)
Sayının karekökünü alın. Tam sayıya dönüştür. Meydanı al. Sayılar eşitse, o zaman tam bir karedir, aksi halde değil.
152415789666209426002111556165263283035677489 gibi büyük bir kare için yanlıştır .
Yuvarlak karekök için ikili arama yapabilirsiniz. Orijinal değerle eşleşip eşleşmediğini görmek için sonucun karesini alın.
FogleBirds cevabıyla muhtemelen daha iyi durumdasınız - yine de dikkatli olun, çünkü kayan nokta aritmetiği yaklaşıktır, bu da bu yaklaşımı geçersiz kılabilir. Prensipte büyük bir tam sayıdan, tam kareden bir fazla olan yanlış bir pozitif elde edebilirsiniz, örneğin, kayıp hassasiyet nedeniyle.
Bu yanıt, belirttiğiniz soruyla ilgili değildir, ancak gönderdiğiniz kodda gördüğüm örtük bir soruyla, yani "bir şeyin tam sayı olup olmadığı nasıl kontrol edilir?"
Genel olarak bu soruya alacağınız ilk cevap "Yapma!" Ve Python'da yazım denetiminin genellikle yapılacak doğru şey olmadığı doğrudur.
Ancak bu nadir istisnalar için, sayının dize temsilinde bir ondalık nokta aramak yerine, yapılacak şey isinstance işlevini kullanmaktır :
>>> isinstance(5,int)
True
>>> isinstance(5.0,int)
False
Elbette bu, bir değerden çok değişken için geçerlidir. Değerin tam sayı olup olmadığını belirlemek isteseydim , şunu yapardım:
>>> x=5.0
>>> round(x) == x
True
Ancak herkesin ayrıntılı olarak ele aldığı gibi, bu tür şeylerin oyuncak olmayan örneklerinin çoğunda dikkate alınması gereken kayan nokta konuları vardır.
Bir aralık üzerinden döngü yapmak ve her sayı için tam kare OLMAYAN bir şey yapmak istiyorsanız, şöyle bir şey yapabilirsiniz:
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
Tam kare olan her sayı için bir şeyler yapmak istiyorsanız, oluşturucu daha da kolay:
(n * n for n in range(upper))
Bunun işe yaradığını ve çok basit olduğunu düşünüyorum:
import math
def is_square(num):
sqrt = math.sqrt(num)
return sqrt == int(sqrt)
152415789666209426002111556165263283035677490 gibi büyük kare olmayanlar için yanlıştır .
set
Ne zaman x in seen
olduğunu True
:
x
511, 256, 129, 68, 41, 32, 31 , 31 dizisini üretir ;Bu nedenle, akım bir x
öncekine eşit veya daha büyük olduğunda durmak yeterlidir :
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)
1 <n <10 ** 7 için test edilen orijinal algoritma ile eşdeğerlik. Aynı aralıkta, bu biraz daha basit varyant yaklaşık 1,4 kat daha hızlıdır.
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')
Buradaki fikir, i = 1'den kata (sqrt (n)) kadar bir döngü çalıştırmak ve ardından karesinin n yapıp yapmadığını kontrol etmektir.
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;
}
import math
def is_square(n):
sqrt = math.sqrt(n)
return sqrt == int(sqrt)
152415789666209426002111556165263283035677490 gibi büyük kare olmayan için başarısız olur .