Wie schreibt man eine eigene Funktion, um die genaueste Quadratwurzel einer ganzen Zahl zu finden?
Nachdem es googeln, fand ich diese (aus seinem archivierten Original - Link ), aber zuerst habe ich es nicht vollständig erhalten, und zweitens ist es zu annähernd.
Nehmen Sie die Quadratwurzel als nächste Ganzzahl (zur tatsächlichen Wurzel) oder als Gleitkomma an.
algorithm
function
math
square-root
newtons-method
Hellblauer Punkt
quelle
quelle
find where [it](http://nlindblad.org/2007/04/04/write-your-own-square-root-function/) has been moved
Lassen Sie mich das Webarchiv einbinden, anstatt zu beschuldigen, es nicht als lahme Ausrede tun zu können .Antworten:
Das Folgende berechnet den Boden (sqrt (N)) für N> 0:
Dies ist eine Version von Newtons Methode in Crandall & Pomerance, "Prime Numbers: A Computational Perspective". Der Grund, warum Sie diese Version verwenden sollten, ist, dass Personen, die wissen, was sie tun, bewiesen haben, dass sie genau auf dem Boden der Quadratwurzel konvergiert. Dies ist einfach, sodass die Wahrscheinlichkeit eines Implementierungsfehlers gering ist. Es ist auch schnell (obwohl es möglich ist, einen noch schnelleren Algorithmus zu konstruieren - aber das richtig zu machen ist viel komplexer). Eine ordnungsgemäß implementierte binäre Suche kann für sehr kleine N schneller sein, aber dort können Sie auch eine Nachschlagetabelle verwenden.
Um auf die nächste ganze Zahl zu runden , berechnen Sie einfach t = floor (sqrt (4N)) mit dem obigen Algorithmus. Wenn das niedrigstwertige Bit von t gesetzt ist, wählen Sie x = (t + 1) / 2; Andernfalls wählen Sie t / 2. Beachten Sie, dass dies auf ein Unentschieden rundet; Sie können auch abrunden (oder auf gerade runden), indem Sie prüfen, ob der Rest ungleich Null ist (dh ob t ^ 2 == 4N).
Beachten Sie, dass Sie keine Gleitkomma-Arithmetik verwenden müssen. In der Tat sollten Sie nicht. Dieser Algorithmus sollte vollständig unter Verwendung von Ganzzahlen implementiert werden (insbesondere geben die Funktionen floor () nur an, dass eine reguläre Ganzzahldivision verwendet werden sollte).
quelle
S
undS
habenK
Ziffern. Dann10^K <= S <= 10^{K+1}
. Dies impliziert10^(2K) <= S**2 < 10^(2k+2)
. Das heißt, wenn Sie Quadratwurzel von finden möchtenN
, hat es eine Länge zwischen der Hälfte der Länge vonN
und eine Nummer eins größer. Letzteres ist also ein guter Ausgangspunkt. Diese Zeile macht es, aber mit 2 als Basis.Abhängig von Ihren Anforderungen kann eine einfache Divide-and-Conquer-Strategie verwendet werden. Es konvergiert nicht so schnell wie einige andere Methoden, aber für Anfänger ist es möglicherweise viel einfacher zu verstehen. Da es sich um einen O (log n) -Algorithmus handelt (der den Suchraum bei jeder Iteration halbiert), beträgt der schlechteste Fall für einen 32-Bit-Float 32 Iterationen.
Angenommen, Sie möchten die Quadratwurzel von 62.104. Sie wählen einen Wert auf halbem Weg zwischen 0 und diesem und quadrieren ihn. Wenn das Quadrat höher als Ihre Zahl ist, müssen Sie sich auf Zahlen konzentrieren, die kleiner als der Mittelpunkt sind. Wenn es zu niedrig ist, konzentrieren Sie sich auf die höheren.
Mit echter Mathematik könnten Sie den Suchraum für immer in zwei Teile teilen (wenn er keine rationale Quadratwurzel hat). In der Realität wird den Computern irgendwann die Präzision ausgehen und Sie haben Ihre Annäherung. Das folgende C-Programm veranschaulicht den Punkt:
#include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { float val, low, high, mid, oldmid, midsqr; int step = 0; // Get argument, force to non-negative. if (argc < 2) { printf ("Usage: sqrt <number>\n"); return 1; } val = fabs (atof (argv[1])); // Set initial bounds and print heading. low = 0; high = mid = val; oldmid = -1; printf ("%4s %10s %10s %10s %10s %10s %s\n", "Step", "Number", "Low", "High", "Mid", "Square", "Result"); // Keep going until accurate enough. while (fabs(oldmid - mid) >= 0.00001) { oldmid = mid; // Get midpoint and see if we need lower or higher. mid = (high + low) / 2; midsqr = mid * mid; printf ("%4d %10.4f %10.4f %10.4f %10.4f %10.4f ", ++step, val, low, high, mid, midsqr); if (mid * mid > val) { high = mid; printf ("- too high\n"); } else { low = mid; printf ("- too low\n"); } } // Desired accuracy reached, print it. printf ("sqrt(%.4f) = %.4f\n", val, mid); return 0; }
Hier sind ein paar Läufe, damit Sie hoffentlich eine Vorstellung davon bekommen, wie es funktioniert. Für 77:
Für 62.104:
Für 49:
quelle
Eine einfache (aber nicht sehr schnelle) Methode zur Berechnung der Quadratwurzel von X:
squareroot(x) if x<0 then Error a = 1 b = x while (abs(a-b)>ErrorMargin) a = (a+b)/2 b = x/a endwhile return a;
Beispiel: Quadratwurzel (70000)
Wie Sie sehen können, definiert es eine obere und eine untere Grenze für die Quadratwurzel und verengt die Grenze, bis ihre Größe akzeptabel ist.
Es gibt effizientere Methoden, aber diese veranschaulicht den Prozess und ist leicht zu verstehen.
Achten Sie nur darauf, die Errormargin auf 1 zu setzen, wenn Sie Ganzzahlen verwenden. Andernfalls haben Sie eine Endlosschleife.
quelle
do … while(a-b>ErrorMargin)
verwenden, vermeiden Sie die Verwendung der abs () -Funktion und machen sie etwas schnellerLassen Sie mich auf eine äußerst interessante Methode zur Berechnung einer inversen Quadratwurzel 1 / sqrt (x) hinweisen, die in der Welt des Spieldesigns eine Legende ist, weil sie unglaublich schnell ist. Oder warten Sie, lesen Sie den folgenden Beitrag:
http://betterexplained.com/articles/understanding-quakes-fast-inverse-square-root/
PS: Ich weiß, du willst nur die Quadratwurzel, aber die Eleganz des Bebens hat meinen ganzen Widerstand überwunden :)
Übrigens spricht der oben erwähnte Artikel auch irgendwo über die langweilige Newton-Raphson-Näherung.
quelle
Natürlich ist es ungefähr; So funktioniert Mathe mit Gleitkommazahlen.
Wie auch immer, der Standardweg ist die Newtonsche Methode . Dies entspricht in etwa der Verwendung von Taylors Serie, die mir sofort in den Sinn kommt.
quelle
f(x)=x^2
jedoch überall konvex ist, funktioniert die Newton-Methode unabhängig vom Startpunkt recht gut.Berechnen Sie die Quadratwurzel mit beliebiger Genauigkeit in Python
#!/usr/bin/env python import decimal def sqrt(n): assert n > 0 with decimal.localcontext() as ctx: ctx.prec += 2 # increase precision to minimize round off error x, prior = decimal.Decimal(n), None while x != prior: prior = x x = (x + n/x) / 2 # quadratic convergence return +x # round in a global context decimal.getcontext().prec = 80 # desirable precision r = sqrt(12345) print r print r == decimal.Decimal(12345).sqrt()
Ausgabe:
quelle
Es ist eine häufige Interviewfrage, die von Facebook usw. gestellt wird. Ich denke nicht, dass es eine gute Idee ist, die Newton-Methode in einem Interview zu verwenden. Was ist, wenn der Interviewer Sie nach dem Mechanismus der Newtonschen Methode fragt, wenn Sie ihn nicht wirklich verstehen?
Ich habe eine binäre suchbasierte Lösung in Java bereitgestellt, die meiner Meinung nach jeder verstehen kann.
Sie können meinen Code hier testen: leetcode: sqrt (x)
quelle
Fand einen großartigen Artikel über Integer Square Roots .
Dies ist eine leicht verbesserte Version, die dort vorgestellt wird:
quelle
Hier ist eine Möglichkeit, mithilfe der Trigonometrie eine Quadratwurzel zu erhalten. Es ist nicht der schnellste Algorithmus, aber es ist präzise. Code ist in Javascript:
quelle
Es gibt einen Algorithmus, den ich in der Schule studiert habe, mit dem Sie exakte Quadratwurzeln berechnen können (oder mit beliebig großer Genauigkeit, wenn die Wurzel eine irrationale Zahl ist). Es ist definitiv langsamer als Newtons Algorithmen, aber es ist genau. Nehmen wir an, Sie möchten die Quadratwurzel von 531.3025 berechnen
Als erstes teilen Sie Ihre Zahl beginnend mit dem Dezimalpunkt in zweistellige Gruppen:
{5} {31}. {30} {25}
Dann:
1) Finden Sie die nächste Quadratwurzel für die erste Gruppe, die kleiner oder gleich der ist tatsächliche Quadratwurzel der ersten Gruppe: sqrt ({5})> = 2. Diese Quadratwurzel ist die erste Ziffer Ihrer endgültigen Antwort. Bezeichnen wir die Ziffern, die wir bereits von unserer letzten Quadratwurzel gefunden haben, als B. Also
berechnen Sie im Moment B = 2. 2) Berechnen Sie als nächstes die Differenz zwischen {5} und B ^ 2: 5 - 4 = 1.
3) Für alle nachfolgenden Zweistellige Gruppen führen Folgendes aus:
Multiplizieren Sie den Rest mit 100 und fügen Sie ihn dann der zweiten Gruppe hinzu: 100 + 31 = 131.
Finden Sie X - nächste Ziffer Ihrer Wurzel, so dass 131> = ((B * 20) + X) * X. X = 3. 43 * 3 = 129 <131. Jetzt B = 23. Auch weil Sie keine zweistelligen Gruppen mehr links von den Dezimalstellen haben, haben Sie alle ganzzahligen Ziffern Ihrer endgültigen Wurzel gefunden.
4) Wiederholen Sie dies für {30} und {25}. Sie haben also:
{30}: 131 - 129 = 2. 2 * 100 + 30 = 230> = (23 * 2 * 10 + X) * X -> X = 0 -> B = 23,0
{25}: 230 - 0 = 230. 230 * 100 + 25 = 23025. 23025> = (230 * 2 * 10 + X) * X -> X = 5 -> B = 23.05
Endergebnis = 23.05.
Der Algorithmus sieht auf diese Weise kompliziert aus, aber es ist viel einfacher, wenn Sie ihn auf Papier mit derselben Notation ausführen, die Sie für die "lange Teilung" verwenden, die Sie in der Schule gelernt haben, außer dass Sie keine Teilung durchführen, sondern stattdessen die Quadratwurzel berechnen.
quelle
quelle
Das erste, was mir in den Sinn kommt, ist: Dies ist ein guter Ort, um die binäre Suche zu verwenden (inspiriert von diesen großartigen Tutorials ).
Um die Quadratwurzel von zu
vaule
finden, suchen wir nach dem Ort,number
an(1..value)
dem der Prädiktor zum ersten Mal wahr ist. Der Prädiktor, den wir wählen, istnumber * number - value > 0.00001
.quelle
Verwenden Sie die binäre Suche
quelle
Im Allgemeinen kann die Quadratwurzel einer Ganzzahl (wie z. B. 2) nur angenähert werden (nicht aufgrund von Problemen mit der Gleitkomma-Arithmetik, sondern weil es sich um irrationale Zahlen handelt, die nicht genau berechnet werden können).
Natürlich sind einige Annäherungen besser als andere. Ich meine natürlich, dass der Wert 1,732 eine bessere Annäherung an die Quadratwurzel von 3 ist als 1,7
Die Methode, die der Code unter dem von Ihnen angegebenen Link verwendet, funktioniert, indem eine erste Näherung verwendet und zur Berechnung einer besseren Näherung verwendet wird.
Dies wird als Newtonsche Methode bezeichnet, und Sie können die Berechnung mit jeder neuen Näherung wiederholen, bis sie für Sie genau genug ist.
Tatsächlich muss es eine Möglichkeit geben, zu entscheiden, wann die Wiederholung gestoppt werden soll, sonst läuft sie für immer.
Normalerweise hören Sie auf, wenn der Unterschied zwischen den Näherungen geringer ist als ein von Ihnen festgelegter Wert.
EDIT: Ich glaube nicht, dass es eine einfachere Implementierung geben kann als die beiden, die Sie bereits gefunden haben.
quelle
Die Umkehrung, wie der Name schon sagt, aber manchmal "nah genug" ist "nah genug"; eine interessante Lektüre trotzdem.
Ursprung von Quake3s Fast InvSqrt ()
quelle
Eine einfache Lösung, die mit der Float-Quadratwurzel und beliebiger Genauigkeit mithilfe der binären Suche umgehen kann
in Rubin codiert
quelle
Angenommen, wir versuchen, die Quadratwurzel von 2 zu finden, und Sie haben eine Schätzung von 1,5. Wir sagen a = 2 und x = 1,5. Um eine bessere Schätzung zu berechnen, teilen wir a durch x. Dies ergibt einen neuen Wert y = 1,333333. Wir können dies jedoch nicht einfach als unsere nächste Schätzung nehmen (warum nicht?). Wir müssen es mit der vorherigen Schätzung mitteln. Unsere nächste Schätzung, xx, wird also (x + y) / 2 oder 1,416666 sein.
Epsilon bestimmt, wie genau die Approximation sein muss. Die Funktion sollte die erste erhaltene Näherung x zurückgeben, die abs (x * x - a) <epsilon erfüllt, wobei abs (x) der absolute Wert von x ist.
quelle
Nun, es gibt bereits einige Antworten, aber hier ist meine. Es ist der einfachste Code (für mich), hier ist der Algorithmus dafür.
Und Code in Python 2.7:
quelle
Berechnung der Quadratwurzel einer Zahl mit Hilfe der eingebauten Funktion
quelle