Wie kann ich überprüfen, ob eine Zahl ein perfektes Quadrat ist?
Geschwindigkeit ist im Moment kein Problem, nur zu arbeiten.
python
math
perfect-square
Scharfsinn
quelle
quelle
Antworten:
Das Problem bei der Verwendung von Gleitkomma-Berechnungen (
math.sqrt(x)
oderx**0.5
) besteht darin, dass Sie nicht wirklich sicher sein können, ob sie genau sind (bei ausreichend großen Ganzzahlenx
ist dies nicht der Fall und kann sogar überlaufen). Zum Glück (wenn man es nicht eilig hat ;-) gibt es viele reine ganzzahlige Ansätze, wie zum Beispiel die folgenden ...:Hinweis: Es basiert auf dem "babylonischen Algorithmus" für Quadratwurzel, siehe Wikipedia . Es funktioniert für jede positive Zahl, für die Sie genügend Speicher haben, damit die Berechnung abgeschlossen werden kann ;-).
Edit : sehen wir uns ein Beispiel an ...
dies druckt wie gewünscht (und in angemessener Zeit auch ;-):
Bevor Sie Lösungen vorschlagen, die auf Gleitkomma-Zwischenergebnissen basieren, stellen Sie bitte sicher, dass sie in diesem einfachen Beispiel korrekt funktionieren - es ist nicht so schwer (Sie benötigen nur ein paar zusätzliche Überprüfungen, falls das berechnete Quadrat etwas abweicht) ein bisschen Sorgfalt.
Und dann versuchen Sie es mit
x**7
und finden Sie einen cleveren Weg, um das Problem zu umgehen, das Sie bekommen werden.Sie müssen immer klüger werden, da die Zahlen natürlich weiter wachsen.
Wenn ich es eilig hätte, würde ich natürlich gmpy verwenden - aber dann bin ich eindeutig voreingenommen ;-).
Ja, ich weiß, das ist einfach so einfach, dass es sich wie Betrug anfühlt (ein bisschen so, wie ich mich generell gegenüber Python fühle ;-) - überhaupt keine Klugheit, nur perfekte Direktheit und Einfachheit (und im Fall von gmpy reine Geschwindigkeit ; -) ...
quelle
set([x])
={x}
set
ovekill? Konvergiert Babylonian nicht einfach dahinint(sqrt(x))
, wo wir nur prüfen müssen, obprev != next
?Verwenden Sie die Newton-Methode, um schnell die nächste ganzzahlige Quadratwurzel zu ermitteln, sie dann zu quadrieren und festzustellen, ob es sich um Ihre Zahl handelt. Siehe isqrt .
Python ≥ 3.8 hat
math.isqrt
. Wenn eine ältere Version von Python, suchen Sie nach der „def isqrt(n)
“ Implementierung hier .quelle
Da Sie sich bei Gleitkommaberechnungen (wie diesen Methoden zur Berechnung der Quadratwurzel) niemals auf genaue Vergleiche verlassen können, wäre eine weniger fehleranfällige Implementierung
Stellen Sie sich vor,
integer
ist9
.math.sqrt(9)
könnte sein3.0
, aber es könnte auch so etwas wie2.99999
oder sein3.00001
, daher ist es nicht zuverlässig, das Ergebnis sofort zu quadrieren. Wenn wir wissen, dass diesint
den Mindestwert erfordert, erhalten0.5
wir den gewünschten Wert, wenn wir uns in einem Bereich befinden, in dem diefloat
Auflösung noch fein genug ist, um Zahlen in der Nähe der gesuchten darzustellen .quelle
if int(root + 0.5) ** 2 == integer:
wenn wir unsint
wiefloor
für die Zahlen verhalten, die uns wichtig sind.math.sqrt(9)
wirklich jemals sein kann2.99999
? Pythonsfloat
Karten sind Cs zugeordnetdouble
, aber ich denke, sogar ein 16-Bit-FP-Typ hat eine höhere Genauigkeit. Wenn Sie also einen C-Compiler hätten, der 8-Bit-FP ("Minifloats") alsdouble
Typ verwendet? Ich nehme an, es ist technisch möglich, aber es scheint mir unwahrscheinlich, dass dies auf jedem Computer der Fall ist, auf dem heute Python ausgeführt wird.math.sqrt(9)
zurückkehren wird2.99999
an einem bestimmten System, aber das tatsächliche Ergebnis ist systemabhängig und kann nicht genau sein erwarten.Wenn Sie interessiert sind, habe ich eine rein mathematische Antwort auf eine ähnliche Frage bei math stackexchange: "Perfekte Quadrate schneller erkennen als durch Extrahieren der Quadratwurzel" .
Meine eigene Implementierung von isSquare (n) ist vielleicht nicht die beste, aber ich mag es. Ich habe mehrere Monate in Mathe-Theorie, digitaler Berechnung und Python-Programmierung studiert und mich mit anderen Mitwirkenden usw. verglichen, um wirklich mit dieser Methode zu klicken. Ich mag seine Einfachheit und Effizienz. Ich habe nicht besser gesehen. Sag mir was du denkst.
Ziemlich einfach. Zuerst wird überprüft, ob wir eine Ganzzahl haben, und zwar eine positive. Sonst hat es keinen Sinn. Es lässt 0 als True durch (notwendig oder der nächste Block ist eine Endlosschleife).
Der nächste Codeblock entfernt systematisch Potenzen von 4 in einem sehr schnellen Subalgorithmus unter Verwendung von Bitverschiebungs- und Bitlogikoperationen. Wir finden letztendlich nicht das isSquare unseres ursprünglichen n, sondern eines k <n, das nach Möglichkeit um Potenzen von 4 verkleinert wurde. Dies reduziert die Größe der Zahl, mit der wir arbeiten, und beschleunigt die babylonische Methode erheblich, beschleunigt aber auch andere Überprüfungen.
Der dritte Codeblock führt einen einfachen booleschen Bitlogiktest durch. Die niedrigstwertigen drei binären Ziffern eines perfekten Quadrats sind 001. Immer. Außer für führende Nullen, die sich ohnehin aus Potenzen von 4 ergeben, die bereits berücksichtigt wurden. Wenn der Test nicht bestanden wird, wissen Sie sofort, dass es sich nicht um ein Quadrat handelt. Wenn es vorbei ist, können Sie nicht sicher sein.
Wenn wir für einen Testwert eine 1 erhalten, war die Testnummer ursprünglich eine Potenz von 4, einschließlich vielleicht 1 selbst.
Wie der dritte Block testet der vierte den Einstellenwert in Dezimalzahl unter Verwendung eines einfachen Moduloperators und neigt dazu, Werte zu erfassen, die durch den vorherigen Test rutschen. Auch ein Mod 7, Mod 8, Mod 9 und Mod 13 Test.
Der fünfte Codeblock sucht nach einigen der bekannten perfekten quadratischen Muster. Zahlen, die mit 1 oder 9 enden, wird ein Vielfaches von vier vorangestellt. Und Zahlen, die mit 5 enden, müssen mit 5625, 0625, 225 oder 025 enden. Ich hatte andere eingeschlossen, aber festgestellt, dass sie redundant waren oder nie tatsächlich verwendet wurden.
Schließlich ähnelt der sechste Codeblock sehr der Antwort des Top-Antworters - Alex Martelli -. Findet die Quadratwurzel im Grunde genommen unter Verwendung des alten babylonischen Algorithmus, beschränkt sie jedoch auf ganzzahlige Werte, während Gleitkommawerte ignoriert werden. Dies gilt sowohl für die Geschwindigkeit als auch für die Erweiterung der Größen von Werten, die getestet werden können. Ich habe Mengen anstelle von Listen verwendet, weil es viel weniger Zeit in Anspruch nimmt, ich habe Bitverschiebungen anstelle von Division durch zwei verwendet und ich habe einen anfänglichen Startwert viel effizienter gewählt.
Übrigens habe ich die von Alex Martelli empfohlene Testnummer sowie einige Zahlen getestet, die um viele Größenordnungen größer sind, wie zum Beispiel:
druckte die folgenden Ergebnisse:
Und das in 0,33 Sekunden.
Meiner Meinung nach funktioniert mein Algorithmus mit allen Vorteilen genauso wie der von Alex Martelli, hat jedoch den zusätzlichen Vorteil hocheffizienter Ablehnungen bei einfachen Tests, die viel Zeit sparen, ganz zu schweigen von der Verringerung der Größe der Testnummern um Potenzen von 4, die Geschwindigkeit, Effizienz, Genauigkeit und die Größe der überprüfbaren Zahlen verbessert. Wahrscheinlich besonders in Nicht-Python-Implementierungen.
Ungefähr 99% aller ganzen Zahlen werden als nicht quadratisch abgelehnt, bevor die babylonische Wurzelextraktion überhaupt implementiert wird, und in 2/3 der Zeit, die der babylonische benötigt, um die ganze Zahl abzulehnen. Und obwohl diese Tests den Prozess nicht wesentlich beschleunigen, beschleunigt die Reduzierung aller Testzahlen auf eine ungerade durch Aufteilen aller Potenzen von 4 den babylonischen Test wirklich .
Ich habe einen Zeitvergleichstest gemacht. Ich habe alle ganzen Zahlen von 1 bis 10 Millionen nacheinander getestet. Mit der babylonischen Methode allein (mit meiner speziell zugeschnittenen anfänglichen Vermutung) dauerte meine Oberfläche 3 durchschnittlich 165 Sekunden (mit 100% Genauigkeit). Mit nur den logischen Tests in meinem Algorithmus (mit Ausnahme des Babylonischen) dauerte es 127 Sekunden. 99% aller ganzen Zahlen wurden als Nicht-Quadrat zurückgewiesen, ohne versehentlich perfekte Quadrate abzulehnen. Von diesen ganzen Zahlen waren nur 3% perfekte Quadrate (eine viel höhere Dichte). Unter Verwendung des obigen vollständigen Algorithmus, der sowohl die logischen Tests als auch die babylonische Wurzelextraktion verwendet, haben wir eine 100% ige Genauigkeit und einen Testabschluss in nur 14 Sekunden. Das Testen der ersten 100 Millionen Ganzzahlen dauert ungefähr 2 Minuten und 45 Sekunden.
EDIT: Ich konnte die Zeit weiter verkürzen. Ich kann jetzt die ganzen Zahlen 0 bis 100 Millionen in 1 Minute 40 Sekunden testen. Es wird viel Zeit verschwendet, um den Datentyp und die Positivität zu überprüfen. Beseitigen Sie die ersten beiden Überprüfungen und ich habe das Experiment um eine Minute verkürzt. Man muss davon ausgehen, dass der Benutzer klug genug ist, um zu wissen, dass Negative und Floats keine perfekten Quadrate sind.
quelle
Ein perfektes Quadrat ist eine Zahl, die als Produkt zweier gleicher Ganzzahlen ausgedrückt werden kann.
math.sqrt(number)
Rückgabe afloat
.int(math.sqrt(number))
wirft das Ergebnis aufint
.Wenn die Quadratwurzel eine ganze Zahl ist, wie zum Beispiel 3, dann
math.sqrt(number) - int(math.sqrt(number))
ist 0 und dieif
Anweisung istFalse
. Wenn die Quadratwurzel eine reelle Zahl wie 3,2 war, wird sieTrue
gedruckt und "es ist kein perfektes Quadrat" gedruckt.Bei einem großen Nichtquadrat wie 152415789666209426002111556165263283035677490 schlägt dies fehl.
quelle
if (math.sqrt(number)-int(math.sqrt(number))):
zu einera=math.sqrt(number)
anderen Zeile für :if a-int(a):
. Dies liegt daran, dass die Quadratwurzel nur einmal berechnet werden muss, was imo für großes n von Bedeutung istDies kann mithilfe des
decimal
Moduls gelöst werden , um Quadratwurzeln mit beliebiger Genauigkeit und einfache Überprüfungen auf "Genauigkeit" zu erhalten:Zur Demonstration mit wirklich großen Werten:
Wenn Sie den getesteten Wert vergrößern, wird dies schließlich ziemlich langsam (dauert bei einem 200.000-Bit-Quadrat fast eine Sekunde), bei moderateren Zahlen (z. B. 20.000 Bit) ist es jedoch immer noch schneller, als ein Mensch es bemerken würde Einzelwerte (~ 33 ms auf meiner Maschine). Da Geschwindigkeit jedoch nicht Ihr Hauptanliegen war, ist dies eine gute Möglichkeit, dies mit den Standardbibliotheken von Python zu tun.
Natürlich wäre es viel schneller zu verwenden
gmpy2
und nur zu testengmpy2.mpz(x).is_square()
, aber wenn Pakete von Drittanbietern nicht Ihr Ding sind, funktioniert das oben genannte ziemlich gut.quelle
Ich habe gerade eine geringfügige Abweichung von einigen der obigen Beispiele in einem anderen Thread veröffentlicht ( Finden perfekter Quadrate ) und dachte, ich würde eine geringfügige Abweichung von dem, was ich hier veröffentlicht habe, einfügen (wobei nsqrt als temporäre Variable verwendet wird), falls dies von Interesse ist. verwenden:
Es ist falsch für ein großes Nichtquadrat wie 152415789666209426002111556165263283035677490.
quelle
Meine Antwort lautet:
Es macht im Grunde eine Quadratwurzel, dann modulo um 1, um den ganzzahligen Teil zu entfernen, und wenn das Ergebnis 0 ist, geben Sie es zurück,
True
andernfalls geben Sie es zurückFalse
. In diesem Fall kann x eine beliebige große Zahl sein, nur nicht so groß wie die maximale Float-Zahl, die Python verarbeiten kann: 1.7976931348623157e + 308Es ist falsch für ein großes Nichtquadrat wie 152415789666209426002111556165263283035677490.
quelle
Das ist meine Methode:
Nimm die Quadratwurzel der Zahl. In eine Ganzzahl konvertieren. Nimm den Platz. Wenn die Zahlen gleich sind, ist es ein perfektes Quadrat, sonst nicht.
Es ist falsch für ein großes Quadrat wie 152415789666209426002111556165263283035677489.
quelle
Sie könnten binär nach der gerundeten Quadratwurzel suchen. Quadrieren Sie das Ergebnis, um festzustellen, ob es mit dem ursprünglichen Wert übereinstimmt.
Mit der Antwort von FogleBirds sind Sie wahrscheinlich besser dran - seien Sie jedoch vorsichtig, da die Gleitkomma-Arithmetik ungefähr ist, was diesen Ansatz beeinträchtigen kann. Sie könnten im Prinzip ein falsches Positiv aus einer großen Ganzzahl erhalten, die mehr als ein perfektes Quadrat ist, beispielsweise aufgrund von Genauigkeitsverlusten.
quelle
quelle
Diese Antwort bezieht sich nicht auf Ihre angegebene Frage, sondern auf eine implizite Frage, die ich in dem von Ihnen geposteten Code sehe, z. B. "Wie kann überprüft werden, ob etwas eine Ganzzahl ist?"
Die erste Antwort auf diese Frage lautet im Allgemeinen "Nicht!" Und es ist wahr, dass in Python Typchecking normalerweise nicht das Richtige ist.
Für diese seltenen Ausnahmen müssen Sie jedoch nicht nach einem Dezimalpunkt in der Zeichenfolgendarstellung der Zahl suchen, sondern die isinstance- Funktion verwenden:
Dies gilt natürlich eher für die Variable als für einen Wert. Wenn ich feststellen wollte, ob der Wert eine Ganzzahl ist, würde ich Folgendes tun:
Aber wie alle anderen ausführlich behandelt haben, gibt es Gleitkomma-Probleme, die in den meisten Nicht-Spielzeug-Beispielen dieser Art zu berücksichtigen sind.
quelle
Wenn Sie einen Bereich durchlaufen und für jede Zahl etwas tun möchten, das KEIN perfektes Quadrat ist, können Sie Folgendes tun:
Wenn Sie für jede Zahl, die ein perfektes Quadrat ist, etwas tun möchten, ist der Generator noch einfacher:
quelle
Ich denke, dass dies funktioniert und sehr einfach ist:
Es ist falsch für ein großes Nichtquadrat wie 152415789666209426002111556165263283035677490.
quelle
Der Rest oder der Modul der Quadratwurzel der Zahl ohne Rest bedeutet, dass es sich um ein perfektes Quadrat handelt. Modulus ist eine integrierte Funktion in allen Python-Versionen.
Ich habe dies anhand einer Liste perfekter Quadrate von bis zu 1000 überprüft.
quelle
Eine Variante der Lösung von @Alex Martelli ohne
set
Wann
x in seen
istTrue
:x
Sequenz 511, 256, 129, 68, 41, 32, 31 , 31 ;Daher reicht es aus, anzuhalten, sobald der Strom
x
größer oder gleich dem vorherigen ist:Äquivalenz mit dem ursprünglichen Algorithmus, getestet für 1 <n <10 ** 7. Im gleichen Intervall ist diese etwas einfachere Variante etwa 1,4-mal schneller.
quelle
quelle
Die Idee ist, eine Schleife von i = 1 zum Boden (sqrt (n)) zu führen und dann zu überprüfen, ob durch Quadrieren n entsteht.
quelle
Bei einem großen Nichtquadrat wie 152415789666209426002111556165263283035677490 schlägt dies fehl.
quelle