Schnellste Weg, um finden Sie die größte Potenz von 10, die kleiner als x
Gibt es keine schnelle Möglichkeit zu finden die größte Potenz von 10, die kleiner als eine gegebene Zahl?
Ich bin mit diesem Algorithmus, im moment, aber etwas in mir stirbt jedes mal wenn ich es sehe:
10**( int( math.log10(x) ) ) # python
pow( 10, (int) log10(x) ) //C
Ich umsetzen konnte einfach log10
und pow
Funktionen für meine Probleme mit einer Schleife jeden, aber ich bin immer noch Fragen, wenn es ein bisschen Magie für dezimal-zahlen.
- Was ist daran falsch? Es dauert .0161 Mikrosekunden im Durchschnitt durchzuführen
10**(int(math.log10(987654321987654321)))
, das ist eigentlich ziemlich beeindruckend. - reden wir über integers oder floats?
- Der Schnellste Algorithmus ist wahrscheinlich, abhängig von der Größe der
x
. Sie werden wahrscheinlich wollen, um Profil zu einem hybrid-Ansatz. - In meinem Fall
x
ist eine ganze Zahl, aber ich denke, es sollte nicht ändern, dass viel (könnte cast floatx
in einen ganzzahligen Wert und Umgekehrt). - meine Antwort war schneller als andere, theoretisch, Es ist nützlich für die großen Nummern, die nicht 10-stellig.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einen alternativen Algorithmus ist:
Log und power sind teure Operationen. Wenn Sie wollen schnell, Sie wahrscheinlich wollen, um die IEEE binary exponent in der Tabelle, um die Ungefähre Leistung von zehn, und dann prüfen, ob die Mantisse Kräfte, die eine Veränderung von +1 oder nicht. Diese sollte 3 oder 4 integer Maschinen-Anweisungen (alternativ O(1) mit einem ziemlich kleinen-Konstante).
Tabellen:
dann Ihre Berechnung sollte sein:
[Könnten Sie wirklich brauchen, dies zu schreiben, als assembler-squeeze-out jeden letzten Uhr.]
[Dieser code nicht getestet.]
Jedoch, wenn Sie darauf bestehen, tun Sie dies in python, der interpreter-overhead möglicherweise Sumpf die log/exp Zeit und es könnte keine Rolle spielen.
So, wollen Sie schnell, oder wollen Sie kurz-zu-schreiben?
BEARBEITEN 12/23: OP erzählt uns nun, dass sein "x" ist ein integraler Bestandteil. Unter der Annahme, dass es eine 64 (oder 32) bit-Ganzzahl, die meinen Vorschlag noch funktioniert, aber offensichtlich gibt es nicht ein "IEEE_Exponent". Die meisten Prozessoren haben ein "finde zuerst einen" Befehl, wird Ihnen sagen, die Anzahl der 0-bits auf der linken hand (wichtigsten) Teil des Wertes, z.B. führende Nullen; Sie dürften Dies ist im Grunde 64 (oder 32) minus die macht der zwei für den Wert. Angesichts exponent = 64 - leadingzeros, Sie haben die Kraft der zwei Exponenten und der rest des Algorithmus ist im wesentlichen unverändert (Änderungen Links für den Leser).
Wenn der Prozessor nicht finden-ersten-Unterricht, dann ist wahrscheinlich die beste Wette ist, eine ausgewogene Diskriminierung Baum, um zu bestimmen, die Kraft von zehn. Für 64 bit, einen solchen Baum nehmen würde, höchstens 18 vergleicht, um zu bestimmen, der exponent (10^18 ~~ 2^64).
Erstellen Sie ein array von Kräfte des 10. Durchsuchen Sie den größten Wert, der kleiner als x ist.
Wenn x ist ziemlich klein, finden Sie möglicherweise, dass eine lineare Suche bietet bessere Leistung als eine binäre Suche, zum Teil aufgrund zu weniger Filiale mis-Vorhersagen.
Der asymptotisch Schnellste Weg, soweit ich weiß, beinhaltet das wiederholte quadrieren.
Der Algorithmus nimmt logarithmischen Raum und Zeit in N, das ist linear in N ist der Darstellung Größe. [Die Zeit gebunden ist, ist wahrscheinlich ein bisschen schlechter, weil ich vereinfachte optimistisch]
Beachten Sie, dass ich davon ausgegangen beliebig große ganze zahlen (aufpassen für überlauf!), da die naiv-mal-10-bis-über-Algorithmus ist wahrscheinlich schnell genug, beim Umgang mit 32-bit-Ganzzahlen.
Gegeben, dass diese Sprache unabhängig, wenn Sie können, Holen Sie sich die power von beiden, dass diese Zahl ist bedeutsam, z.B. y in x*2^y (das ist die Art, wie die Nummer gespeichert ist, aber ich bin mir nicht sicher, ich habe gesehen, eine einfache Möglichkeit zum Zugriff auf y in irgendeiner Sprache, die ich verwendet habe) dann, wenn
(eine Fließkomma-division)
10^z oder 10^(z+1) wird die Antwort sein, obwohl 10^z ist immer noch nicht so einfach (beg korrigiert werden).
Ich denke der Schnellste Weg ist O(log(log(n))^2), wird die while-Schleife dauert O(log(log(n)) und es kann rekursive Aufruf endlicher Zeit (können wir sagen, dass O(c) wo sehen Sie konstant ist), dem ersten rekursiven Aufruf ist erfolgt log(log(sqrt(n))) Zeit Sekunde dauert .. und die Anzahl von sqrt in sqrt(sqrt(sqrt....(n)) < 10 ist log(log(n)) und Konstante, weil der Maschine Einschränkungen.
In Python:
10**(len(str(int(x)))-1)
Ich zeitlich die Methoden mit den folgenden Variationen in C++ für den Wert
a
einsize_t
Typ (inlining wird die Leistung verbessert, ändert jedoch nicht die relative Reihenfolge).Versuchen 1: Vermehren, bis Sie die Nummer.
Versuch 2: Multiway-wenn (könnte auch programmiert werden, mit Hilfe einer lookup-Tabelle).
Versuch 3: Modifiziert aus findPow10 von @Saaed Amiri, die verwendet Quadratur schneller finden sehr großen Mächte, als zu Versuchen 1.
Versuchen 4: Lookup-Tabelle indiziert mit count leading zeros-Anweisung als pro @Ira Baxter.
Timing ist wie folgt (gcc-4.8)
Den lookup - /multiway-wenn beats alles, was in C++, erfordert aber wissen wir Ganzzahlen sind eine endliche Größe.
try3
ist langsamer alstry1
im test für kleinere Werte der loop-Ende-Wert für eine große Anzahltry3
beatstry1
. In python sind die Dinge schwierig, weil die ganzen zahlen sind nicht begrenzt, so würde ich kombinierentry2
mittry3
schnell zu verarbeiten zahlen bis zu einer bestimmten Grenze dann mit der möglicherweise sehr große zahlen.In python-denke ich-lookup mit Hilfe einer list comprehension ist wahrscheinlich schneller als ein Mehrwege-wenn.