Effiziente (Zyklen wise) Algorithmus zum berechnen modulo 25?
Ich habe einen code, in dem ich bin-computing-x % 25. x nimmt immer einen positiven Wert, sondern seine dynamische Bandbreite ist groß.
Fand ich heraus, dass dieser bestimmte code-Stück-computing-x % 25 ist die Einnahme von großen Zyklen. Ich brauche, es zu optimieren.
Vorberechnete lookup-Tabelle ist ausgeschlossen wegen der möglichen großen Arbeitsspeicher Größe der Tabelle.
Als zweite Ansatz, den ich codiert, ein fragment(C-code) -
mod(a, b)
{
int r = a;
while(r >= b)
{
r = r - b;
}
return r;
}
1.) Wie kann ich diese optimieren, code für weitere Zyklen(squeeze es auf max)?
2.) Gibt es eine ganz andere optimierte Art und Weise zu erreichen x % 25( ich weiß, Ihr nicht einen gemeinsamen Betrieb, aber immer noch auf der Suche für clevere Eingänge die Menschen möglicherweise verwendet haben, in Ihren Erfahrungen, die vielleicht nelp mich.).
Danke.
-AD
EDIT:
Ich denke, mit einer nativen modulo-operator % in C , intern eine division ( /), die ist teuer, auf dem Prozessor bin ich mit.(Keine div-Anweisung). daher versuchen um zu sehen, ob benutzerdefinierte implemetation schlagen können, die inhärenten Berechnung mittels % - operator.
-AD
Compiler Kompromisse machen. Sie müssen nicht immer versuchen, für die Schnellste Geschwindigkeit. Es ist in der Regel ziemlich leicht zu schlagen, ein compiler für einen bestimmten Fall, denn der compiler ist der Umgang mit den Allgemeinen Fall.
"Ich fand heraus, dass diese ... ist die Einnahme von großen Zyklen. Ich brauche, es zu optimieren." Dies ist ein gute Sache zu hören! Eine Optimierung Frage, wo es war tatsächlich lief durch einen profiler.
Wenn Sie identifiziert die Prozessor - eine, die nicht eine Abteilung Betrieb - dann würden Sie besser Antworten schneller.
Down-gestimmt -, weil all die großen-großen Eingang, die Menschen haben in dieser Frage, ohne auch nur einen Hauch von Pflege von der original-poster, geschweige denn ein V-Zeichen für die gesuchte Lösung (stackoverflow.com/a/980973/451461).
InformationsquelleAutor goldenmean | 2009-06-11
Du musst angemeldet sein, um einen Kommentar abzugeben.
Schlage ich die Lektüre Hacker ' s Delight. Es beschreibt sehr schnelle Rest-algorithmen für Konstante Teiler. Sie würde mit ziemlicher Sicherheit schlagen einen generellen Algorithmus.
Update: Hier finden Sie einige Beispiel-code... kann Es wahrscheinlich überarbeitet werden, um zu vermeiden das temporäre long long.
GCC auf x86 wird dieser Algorithmus für die Berechnung
% 25
- überprüfen Sie die Demontage, finden Sie die Magische Zahl, einemull
und einshrl
Anleitung (die Verschiebung wird nur durch 3 und nicht 35, weil der Wert Platzierung in den Registern)Dies ist die richtige Antwort.
GCC sollte die Optimierung der E-Modul durch eine Konstante wie in diesem Fall auf alle Plattform, die es unterstützt
InformationsquelleAutor Johan Kotlinski
Hier ist eine andere Lösung, die ich kam mit:
Diese nicht teilt oder multiplys, nur 27 Vergleiche und maximal 27 Subtraktionen.
Es ist ein wenig schwer, sich davon zu überzeugen, dass das funktioniert, aber es funktioniert (zumindest für nicht-negative Werte von x).
Dem obigen code ist wirklich eine ent-version:
Durch abrollen es wir vermeiden, das loop-Vergleich und auch die Verschiebungen auf Kosten der größeren code. Man könnte sogar teilweise Rollen Sie ihn mit Duff ' s device, wenn Sie das Gefühl so geneigt, aber mit nur 27 Iterationen insgesamt, und wie ein winziges Stück code, pro iteration, würde ich geneigt sein, nur Rollen Sie den ganzen Weg.
Hier ist, wie es funktioniert: Jede nicht-negative ganze Zahl x ausgedrückt werden kann als (n * 25) + k, wobei n eine nicht-negative ganze Zahl ist und k eine ganze Zahl von 0 bis 24. k ist übrigens auch das Ergebnis, das wir wollen, so könnten wir berechnen x - (n * 25) würden wir bekommen unsere Antwort. Wir wollen in der Lage sein, dies zu tun, ohne zu wissen, n-up-front, aber.
Denke über n binäre. Wenn wir wiederum konnten aus jeder der 1-bits würden wir bekommen 0. Ein Weg dies zu tun ist zu beginnen, bei großen Potenzen von 2 und arbeiten uns nach unten, subtrahieren jede Potenz von 2 nur wenn der aktuelle Wert von n größer als oder gleich, dass die macht der 2.
Da beschäftigen wir uns mit (n * 25) wir brauchen eigentlich absteigenden Potenzen von 2 mal 25. Da k streng weniger als 25, und der kleinste divisor, die wir jemals in Betracht ziehen, ist 25, dies funktioniert sogar, wenn wir ' re Umgang mit (n * 25) + k.
Also jeder Vergleich + Subtraktion ist das unwiderrufliche löschen ein bit von n, und wir am Ende sind Links mit k, der Rest.
InformationsquelleAutor Laurence Gonsalves
Da Sie möchten, dass der E-Modul eine Konstante, Sie kann wahrscheinlich schlagen es mit gegenseitigen Multiplikation. Dieses Papier zeigt, wie man eine Division durch eine Konstante in einer solchen Art und Weise, und gegen Ende, wie man den Rest von ihm.
InformationsquelleAutor Nietzche-jou
Hier ist das beste, das ich kommen konnte mit:
Es kommt
x % 25
mitx % 32 + 7 * (x/32)
. Der Wert überschwingen durch ein Vielfaches von25
, die es ermöglicht Rekursion.Leistung scheint ausreichend zu sein: Ein Wert von
x = 2147483647
(akaINT_MAX
) muss 11 Iterationen.InformationsquelleAutor Christoph
Inspiriert wurde ich dazu von Pax Antwort und machte ein mehr allgemeiner Algorithmus.
Subtrahiert Leistung von zwei vielfachen von
b
ausa
bis das Ergebnis gefunden.EDIT: Hinzugefügt den
if
Bedingung, damit es richtig funktioniert.Wenn, als Beispiel, das ist zu tun 100 % 7, es zuerst klappt das 7 * 2 * 2 * 2 * 2 = 112. Dann teilt es 112 (
s
) durch 2 und subtrahieren, dass von 100 (r
) (wenns <= r
) und ständig tut Sie dies, bis die modulo-ist gefunden. Daherdaher 100 % 7 = 2
InformationsquelleAutor David Johnstone
Oh mein <Gottheit der Wahl>. Ich kann nicht glauben, dass einige dieser Antworten.
Erste Sache, wiederholte Subtraktion, auch Pax-version, wird nie, nie, niemals optimal sein. Betrachten Sie die folgenden:
einfach und schnell durch wiederholte Subtraktion, aber:
wird schrecklich langsam, 600+ Iterationen. Das ist ein Durchschnitt von 300 Iterationen für 16-bit-zahlen. Für 32-bit-Nummer, nun, nur, gar nicht dorthin gehen.
Der Schnellste Weg, dies zu tun ist, um lange Teilung. Siehe Niki ' s Antwort.
Aber, dies ist, was der compiler erzeugen, jedenfalls, mindestens, würde man hoffen, dass es das ist, was der compiler generiert wird. Es ist immer am besten, wenn Sie mit einem compiler für eine Nische Prozessor.
Der beste Weg, um diese Fahrt ist nicht das Modul in den ersten Platz. Warum brauchen Sie, um das Modul und kann man wieder den Faktor der code /Algorithmus zu vermeiden, der E-Modul, oder zumindest, machen das E-Modul trivial.
InformationsquelleAutor Skizz
Sich das problem mit dem loop ist, dass es ist O(n) - es werden sehr langsam für große Werte von r ist. Ich würde vorschlagen, so etwas wie dieses:
Aber ich bezweifle, dass dein compiler etwas zu tun, viel teurer als die.
InformationsquelleAutor Niki
Auf viele Prozessoren, integer-Multiplikation ist schneller als division. In diesem blog-post zeigt, wie zu ersetzen, die eine Konstante Ganzzahl-division mit einer Konstanten integer-Multiplikation. Durch eine Neuanordnung der Mathematik ein bisschen können Sie den Rest statt des Quotienten. Beachten Sie jedoch, dass, wenn Sie mit einem mäßig anspruchsvollen compiler, dann ist dies bereits für Sie getan. Sie schreiben einfach
x % 25
und der compiler funktioniert der rest. Sollten Sie den erzeugten Assembler-code für deinen code, überprüfen, ob der compiler hat das nicht getan bereits, bevor Sie diese Optimierung in C. Auch sollte man Messen (Profil) die Leistung vor und nach, um sicherzustellen, dass Sie wirklich sind, die Dinge zu beschleunigen.Looping wird weit langsamer als die division mit dem native-Anleitung für die relativ großen Operanden.
Edit: siehe auch dieses Papier.
InformationsquelleAutor Doug
Wenn Ihr C-compiler ausgerichtet ist, eine CPU mit keine Kluft Unterricht, Sie können ändern Sie Ihren code wie folgt:
Dies funktioniert, indem die Werte in Blöcken von vier, anstatt eine, bis in die Letzte schaltet dann zu subtrahieren Brocken.
Diese sollten Ihren code ausführen, etwa vier mal so schnell (vorausgesetzt
4*b
ist nicht außerhalb der Reichweite Ihres ganzen zahlen). Sie könnten auch legen Sie mehr Schleifen (sagen wir ein8*b
) vor der4*b
man für noch mehr Geschwindigkeit.Anderes, als dass, hand-coding, assembler helfen kann, aber ich glaube, Sie finden durchaus einen Schub von den oben genannten code, ohne dass es.
Wenn du mehr Details wissen, auf dem Weg werden Sie mit dem mod rufen, Sie optimieren es für Ihren Einzelfall. Zum Beispiel, wenn Sie nur wissen wollen modulo-25 von 16-bit-Ganzzahl, die den folgenden code viel schneller als eine simple Schleife mit variable Nenner.
Läuft ein test, ich finde, dass Sie zu tun haben, 10 Millionen Iterationen, bevor ein merklicher Unterschied Auftritt zwischen dem, modulo-code und die Nutzung der
%
- operator (2 Sekunden vs. 0 Sekunden). Bis zu diesem Zeitpunkt waren Sie beide 0 Sekunden, obwohl, dass wurde auf einem schnellen Rechner (besser fürmod25
) und mit einediv
Unterricht (besser für%
operator), so müssten Sie es zum benchmark auf Ihrer eigenen hardware.Dies ist in etwa so schnell, wie Sie wahrscheinlich zu bekommen, ohne dass Ihr code nicht lesbar ist (obwohl selbst das sollte nicht aufhören, wenn Sie bereit sind, fügen viele Kommentare, die erklären, wie es funktioniert).
Einer Allgemeinen Lösung für alle Nenner ist, um den ersten doppelten Nenner (mit bit-Verschiebungen für die Geschwindigkeit) so weit wie möglich, sodass die daraus resultierenden Abzüge minimiert werden. Dann, als der Zähler reduziert, die unterhalb der erhöhten Nenner, halbieren den Nenner und in Gang halten (bis der Nenner ist wieder am start).
Diese tatsächlich ausführt, auf eine Stufe mit der optimierten version des
mod25
oben, während die mehr Allgemeinen Lösung.InformationsquelleAutor paxdiablo
bitte engagieren Sie einige der gesunde Menschenverstand.
Wenn Sie schreiben könnten, C-code, berechnet x % 25-schneller als der compiler, dann würde der compiler verwenden, die schnellere Methode.
Den original-poster dieses fantastische Annahme, dass der compiler die Verwendung einer division. Keine compiler, die ich verwendet habe in den letzten zehn Jahren tun würde. Es ist die Multiplikation durch eine Konstante in der Nähe (2^32 /25) plus einige bit-twiddling, dass Sie nicht in der Lage sein zur Verbesserung von hand.
Gibt es eine Möglichkeit, dass Sie Sie produzieren können schnelleren code als der compiler, um herauszufinden, ob x % 25 == 0, da Sie nicht wirklich benötigen-code berechnet x % 25 richtig, nur code, berechnet x % 25 richtig, wenn es 0 ist, und nicht produzieren eine 0, wenn x % 25 != 0. Einsparungen werden wahrscheinlich im sub-Nanosekunden.
"Wie berechne ich x % c optimal für verschiedene Konstanten c" ist ein nettes puzzle. Compiler-Autoren wie schön Rätseln. Und Sie sind besser auf die Lösung von schönen Rätseln, wie diese, als Sie sind. Vor allem, da Sie nur brauchen eine Lösung, die funktioniert für eine Maschine, wo Sie haben, um zu produzieren, eine Allgemeine Lösung.
InformationsquelleAutor gnasher729
Wenn Sie nicht wie
%
Betreiber:Ich denke, da der OP versucht zu vermeiden, mit Teilung, einen Algorithmus mit einer division, die in es wird nicht viel helfen (ich habe nicht downvote). OP nur diese geklärt nachdem Ihre Antwort obwohl
Genau. OP hat nicht erwähnt zunächst, dass die division sollte auch vermieden werden.
Gut, er sagte, sagen, dass die CPU nicht mit einem div-operator. Sicherlich hätte eine Ahnung? 🙂
Er hat nicht gesagt, dass es zunächst - es erschien erst nach Bearbeiten.
InformationsquelleAutor qrdl
Wenn Sie wissen, dass
b
wird eine Potenz von 2 ist, könnten Sie bitweiseAND
anstelle der modulo-operator. Jedoch, die wikipedia-Seite für modulo scheint zu zeigen, dass C-compiler würde dies feststellen und optimieren aus der modulo jedenfalls.Meh, war gerade mit die einzige Optimierung, die ich denken konnte; vielleicht wird es jemand anderes helfen.
InformationsquelleAutor wkf
Vielleicht nicht die schnellsten, aber einigermaßen effizient. Ich habe keine Zeit zu testen, aber verwenden Sie ein look-up-Tabelle von (Potenzen von 2) * 25 bis auf die maximale Reichweite/2. Dann machen Sie eine Schleife. E. g. Reichweite bis zu 3199 braucht 7 Iterationen.
Wenn Sie eine sehr große Auswahl, aber niedrige Werte häufiger sind, dann könnte es sich lohnen, usng eine binäre hacken zu finden, der Ausgangspunkt.
InformationsquelleAutor Dipstick
Wie es funktioniert: Wir wollen, zu verringern
x
durch große Vielfache von 25 zu reduzieren, den Wert so schnell wie möglich. Wenn der divisor ist zu groß, wechseln wir auf ein kleineres Vielfaches von 25. Wenn der divisor ist schon runter auf 25, dann sind wir fertig.Könnten Sie versuchen, das Experimentieren mit verschiedenen Teiler. Sie wollen einfach nur, um sicherzustellen, dass:
Im obigen code verwendete ich die größte signed-32-bit-Vielfaches von 25 plus die Befugnisse von 25, das scheint vernünftig, aber ich muss zugeben, dass ich nicht sicher bin, dass es optimal.
(BTW: wenn dein compiler nicht tun constant folding-was sehr überraschend-dann möchten Sie vielleicht zu ersetzen, die Obere Grenze
i
mit einem hart codierte Konstante.)Ja, das ist wahr. Ich gepostet, andere Antwort, die genau das macht 27 Iterationen und ausgerollt hat 27 vergleichen und bis zu 27-Abzüge, und funktioniert für alle nicht-negative (signed 32-bit) - Eingänge.
InformationsquelleAutor Laurence Gonsalves
Warum können Sie nicht einfach mit dem operator
%
? Wenn das ist C-code, und die zahlen sind ganz normale "native"int
:s, dann sollte der Schnellste Weg, mit Abstand.InformationsquelleAutor unwind
Gibt es einen Grund, warum Sie nicht verwenden C die eingebaute modulo-operator?
Folgenden edit;
Wenn Ihr rpocessor nicht eingebaute modulo-Unterstützung, dann würde ich immer noch den % - operator aus dem einfachen Grund, dass dein compiler wissen, dass der Prozessor in Frage, der nicht über eine native % - Funktion, und wird wahrscheinlich produzieren asm-code optimal zu emulieren.
Sagen wir es so - ich wäre fasziniert, wenn Sie mit oben kommen kann eine algemeine Algorithmus, der übertrifft whatevr der compiler erzeugt aus den eingebauten operator, notwithsatanding bestimmten Fällen (z.B. nur die 2 niedrigsten Ziffern modulo 100 etc)
Tatsächlich ... hat es 🙂
InformationsquelleAutor PaulJWilliams
Wie etwa:
Update: es ist ziemlich falsch 🙂 Aber die Idee ist da.
InformationsquelleAutor leppie
Ich finde es ziemlich merkwürdig, dass der Betrieb
x % 25
dauert eine lange Zeit (wenn Sie den built-in%
Betreiber ist). Die meisten modernen Prozessoren sollte diese in einer einzigen Instruktion. Ich würde nach anderen Gründen, dass dieser code so lange dauert.BEARBEITEN:
Hier ist ein Algorithmus, der könnte zumindest geben einige Ideen:
256 = 6 (mod 25)
Dies bedeutet, dass, wenn wir eine Zahl schreiben
x
als bytesx3 x2 x1 x0
haben wir, dassx = 6^3*x3 + 6^2*x2 + 6*x1 + x0
(mod 25)Dieser gibt einen Algorithmus für die Reduzierung der Größe der
x
:(hier
(y << 2) + (y << 1) = 4*y + 2*y = 6*y
)Nach dieser
y
haben den gleichen Rest wiex
mod 25.Durchlaufen diese 1, 2 oder 3 mal machen
y
17, 11, oder 9-bit-Zahl, beziehungsweise. Eine dieser Größen ist zwar klein genug, um eine lookup-Tabelle.Ich bezweifle ERNSTHAFT, dass dies schneller sein als die eingebaute
%
Betreiber, obwohl.Ja, aber es war nicht klar von der ursprünglichen Frage, ob das problem war wirklich ein Mangel der DIV-Anweisung oder nicht. Und ich denke immer noch, dass wenn der code zu langsam ist, der erste Gedanke sollte nicht sein, ersetzen Sie den C-Compiler eingebauten arithmetischen Operatoren.
div-Anweisung ist oft (auch auf x86) umgesetzt in Mikrocode, und so langsam.
InformationsquelleAutor CAdaker
Wenn Sie gehalten, Ihre zahlen in BCD oder ein byte-array von Ziffern, das wäre ziemlich einfach. Leider habe ich keine Idee, was Sie tun, in Ihr Programm mit diesen zahlen. Manchmal lohnt sich es zu sehen, wie Sie repräsentieren Ihre Daten nicht als nur bang entfernt auf algorithmen.
InformationsquelleAutor Nosredna
Heres eine Idee
InformationsquelleAutor clinux
Wenn Sie nur unter Berücksichtigung der Zahl 25, die Sie verwenden können, die Tatsache, dass 25 divies eine Ganzzahl, wenn, und nur wenn die beiden letzten Ziffern des ganzzahligen sind 00, 25, 50 oder 75. So bekommen die modulo-Sie betrachten die letzten beiden Ziffern und subtrahieren Sie dann die nächstgelegene 00, 25, 50 oder 75.
Zahlen in binärer form, so ist es nicht leicht, die Arbeit mit dezimal-Ziffern. Und wie finden Sie Ihre nächsten richtigen Teiler? Es ist offensichtlich für Menschen aber es gibt keine solche CPU-Instruktion.
Vielleicht wird sein Prozessor hat eine BCD-Modus. 🙂
Es spielt natürlich vom Kontext abhängen. Zum Beispiel können die Daten zunächst aus einer text-Datei. Obwohl es nun klar von seinem Bearbeiten, das ist wahrscheinlich nicht das, was er suchte, es ist ein Weg, nichtsdestotrotz.
InformationsquelleAutor Bessi