Hier ist eine dumme lustige Frage:
Angenommen, wir müssen eine einfache Operation ausführen, bei der wir die Hälfte des Werts einer Variablen benötigen. Es gibt normalerweise zwei Möglichkeiten, dies zu tun:
y = x / 2.0;
// or...
y = x * 0.5;
Angenommen, wir verwenden die mit der Sprache gelieferten Standardoperatoren. Welche hat eine bessere Leistung?
Ich vermute, Multiplikation ist normalerweise besser, also versuche ich, mich beim Codieren daran zu halten, aber ich möchte dies bestätigen.
Obwohl ich persönlich an der Antwort für Python 2.4-2.5 interessiert bin , können Sie auch eine Antwort für andere Sprachen posten! Und wenn Sie möchten, können Sie auch andere ausgefallenere Methoden (wie die Verwendung von bitweisen Verschiebungsoperatoren) veröffentlichen.
performance
programming-languages
Edmundito
quelle
quelle
Antworten:
Python:
Die Multiplikation ist 33% schneller
Lua:
=> kein wirklicher Unterschied
LuaJIT:
=> es ist nur 5% schneller
Schlussfolgerungen: In Python ist das Multiplizieren schneller als das Teilen. Wenn Sie sich jedoch mit fortgeschritteneren VMs oder JITs der CPU nähern, verschwindet der Vorteil. Es ist durchaus möglich, dass eine zukünftige Python-VM dies irrelevant macht
quelle
Verwenden Sie immer das, was am klarsten ist. Alles andere, was Sie tun, ist, den Compiler zu überlisten. Wenn der Compiler überhaupt intelligent ist, wird er das Beste tun, um das Ergebnis zu optimieren, aber nichts kann den nächsten dazu bringen, Sie nicht für Ihre beschissene Bitshifting-Lösung zu hassen (ich liebe Bit-Manipulation übrigens, es macht Spaß. Aber Spaß! = Lesbar )
Vorzeitige Optimierung ist die Wurzel allen Übels. Denken Sie immer an die drei Optimierungsregeln!
Wenn Sie ein Experte sind und die Notwendigkeit rechtfertigen können, gehen Sie wie folgt vor:
Dinge wie das Entfernen innerer Schleifen, wenn sie nicht benötigt werden, oder das Auswählen einer verknüpften Liste über einem Array für eine Einfügesortierung sind keine Optimierungen, sondern nur Programmieren.
quelle
Ich denke, das wird so pingelig, dass Sie besser tun sollten, was auch immer den Code lesbarer macht. Ich bezweifle, dass irgendjemand den Unterschied jemals bemerken wird, es sei denn, Sie führen die Operationen tausende, wenn nicht millionenfach durch.
Wenn Sie wirklich die Wahl treffen müssen, ist Benchmarking der einzige Weg. Finden Sie heraus, welche Funktionen Ihnen Probleme bereiten, finden Sie heraus, wo in der Funktion die Probleme auftreten, und beheben Sie diese Abschnitte. Ich bezweifle jedoch immer noch, dass eine einzige mathematische Operation (selbst eine, die viele, viele Male wiederholt wurde) eine Ursache für einen Engpass sein würde.
quelle
Die Multiplikation ist schneller, die Division genauer. Sie verlieren etwas an Präzision, wenn Ihre Zahl keine Zweierpotenz ist:
Selbst wenn Sie den Compiler die invertierte Konstante mit perfekter Genauigkeit herausfinden lassen, kann die Antwort dennoch unterschiedlich sein.
Das Geschwindigkeitsproblem spielt wahrscheinlich nur in C / C ++ - oder JIT-Sprachen eine Rolle, und selbst dann nur, wenn sich die Operation in einer Schleife mit einem Engpass befindet.
quelle
y = x * (1.0/3.0);
Der Compiler berechnet im Allgemeinen 1/3 zur Kompilierungszeit. Ja, 1/3 ist in IEEE-754 nicht perfekt darstellbar, aber wenn Sie Gleitkomma-Arithmetik ausführen, verlieren Sie trotzdem an Genauigkeit , egal ob Sie Multiplikation oder Division durchführen, da die Bits niedriger Ordnung gerundet sind. Wenn Sie wissen, dass Ihre Berechnung so empfindlich auf Rundungsfehler reagiert, sollten Sie auch wissen, wie Sie mit dem Problem am besten umgehen können.(1.0/3.0)
mit der Division durch verglichen3.0
. Ich habe bis zu 1.0000036666774155 erreicht, und in diesem Bereich waren 7,3% der Ergebnisse unterschiedlich. Ich nehme an, dass sie sich nur um 1 Bit unterschieden, aber da die IEEE-Arithmetik garantiert auf das nächste korrekte Ergebnis rundet, stehe ich zu meiner Aussage, dass die Division genauer ist. Ob der Unterschied signifikant ist, liegt bei Ihnen.Wenn Sie Ihren Code optimieren möchten, aber dennoch klar sind, versuchen Sie Folgendes:
Der Compiler sollte in der Lage sein, die Teilung zur Kompilierungszeit durchzuführen, damit Sie zur Laufzeit eine Multiplikation erhalten. Ich würde erwarten, dass die Präzision die gleiche ist wie in der
y = x / 2.0
Fall.Wo dies von Bedeutung sein kann, befindet sich ein LOT in eingebetteten Prozessoren, in denen eine Gleitkommaemulation erforderlich ist, um die Gleitkomma-Arithmetik zu berechnen.
quelle
y = x / 2.0;
In der realen Welt müssen Sie den Compiler möglicherweise dazu überreden, eine kostengünstigere Multiplikation durchzuführen. Vielleicht ist es weniger klar, warumy = x * (1.0 / 2.0);
es besser ist, und es wäre klarer,y = x * 0.5;
stattdessen zu sagen . Aber ändern Sie das2.0
zu einem7.0
und ich würde viel lieber seheny = x * (1.0 / 7.0);
alsy = x * 0.142857142857;
.Ich werde nur etwas für die Option "Andere Sprachen" hinzufügen.
C: Da dies nur eine akademische Übung ist, die wirklich keinen Unterschied macht, dachte ich, ich würde etwas anderes beitragen.
Ich habe ohne Optimierungen zur Montage kompiliert und mir das Ergebnis angesehen.
Der Code:
zusammengestellt mit
gcc tdiv.c -O1 -o tdiv.s -S
die Division durch 2:
und die Multiplikation mit 0,5:
Als ich diese
int
s jedoch in ändertedouble
s (was Python wahrscheinlich tun würde), bekam ich Folgendes:Aufteilung:
Multiplikation:
Ich habe keinen dieser Codes bewertet, aber wenn Sie den Code untersuchen, können Sie feststellen, dass die Division durch 2 bei Verwendung von ganzen Zahlen kürzer ist als die Multiplikation mit 2. Bei der Verwendung von Doubles ist die Multiplikation kürzer, da der Compiler die Gleitkomma-Opcodes des Prozessors verwendet wahrscheinlich schneller laufen (aber eigentlich weiß ich es nicht) als sie nicht für den gleichen Vorgang zu verwenden. Letztendlich hat diese Antwort gezeigt, dass die Leistung der Multiplikation mit 0,5 gegenüber der Division durch 2 von der Implementierung der Sprache und der Plattform abhängt, auf der sie ausgeführt wird. Letztendlich ist der Unterschied vernachlässigbar und sollte Sie sich so gut wie nie Sorgen machen, außer in Bezug auf die Lesbarkeit.
Als Randnotiz können Sie sehen, dass in meinem Programm
main()
zurückkehrta + b
. Wenn ich das flüchtige Schlüsselwort wegnehme, werden Sie nie erraten, wie die Assembly aussieht (mit Ausnahme des Programm-Setups):es hat sowohl die Division, Multiplikation als auch Addition in einer einzigen Anweisung durchgeführt! Natürlich müssen Sie sich darüber keine Sorgen machen, wenn der Optimierer respektabel ist.
Entschuldigung für die zu lange Antwort.
quelle
movl $5, %eax
Der Name der Optimierung ist nicht wichtig oder sogar relevant. Sie wollten sich nur auf eine vier Jahre alte Antwort herablassen.Erstens, wenn Sie nicht in C oder ASSEMBLY arbeiten, befinden Sie sich wahrscheinlich in einer höheren Sprache, in der Speicherstillstände und allgemeine Anrufkosten den Unterschied zwischen Multiplizieren und Teilen bis zur Irrelevanz in den Schatten stellen. Wählen Sie also einfach aus, was in diesem Fall besser liest.
Wenn Sie von einem sehr hohen Niveau sprechen, wird es für alles, wofür Sie es wahrscheinlich verwenden, nicht messbar langsamer sein. Sie werden in anderen Antworten sehen, dass Menschen eine Million multiplizieren / dividieren müssen, um einen Unterschied zwischen den beiden im Millisekundenbereich zu messen.
Wenn Sie immer noch neugierig sind, unter dem Gesichtspunkt der Optimierung auf niedriger Ebene:
Divide hat tendenziell eine deutlich längere Pipeline als Multiplikation. Dies bedeutet, dass es länger dauert, bis das Ergebnis angezeigt wird. Wenn Sie den Prozessor jedoch mit nicht abhängigen Aufgaben beschäftigen können, kostet Sie dies nicht mehr als eine Multiplikation.
Wie lange der Pipelineunterschied ist, hängt vollständig von der Hardware ab. Die letzte Hardware, die ich verwendet habe, war ungefähr 9 Zyklen für eine FPU-Multiplikation und 50 Zyklen für eine FPU-Teilung. Hört sich viel an, aber dann würden Sie 1000 Zyklen für einen Speicherfehler verlieren, so dass die Dinge relativiert werden können.
Eine Analogie besteht darin, einen Kuchen in eine Mikrowelle zu stellen, während Sie eine Fernsehsendung ansehen. Die Gesamtzeit, die Sie von der TV-Show entfernt haben, ist, wie lange es gedauert hat, sie in die Mikrowelle zu stellen und aus der Mikrowelle zu nehmen. Den Rest Ihrer Zeit haben Sie noch die TV-Show gesehen. Wenn der Kuchen also 10 Minuten statt 1 Minute gekocht hat, hat er Ihre Fernsehzeit nicht mehr verbraucht.
In der Praxis müssen Sie Pipelines, Cache, Verzweigungsstillstände, Vorhersagen außerhalb der Reihenfolge und Pipeline-Abhängigkeiten verstehen, wenn Sie sich um den Unterschied zwischen Multiplizieren und Teilen kümmern möchten. Wenn dies nicht so klingt, als wollten Sie mit dieser Frage beginnen, besteht die richtige Antwort darin, den Unterschied zwischen den beiden zu ignorieren.
Vor vielen (vielen) Jahren war es absolut wichtig, Teilungen zu vermeiden und immer Multiplikationen zu verwenden, aber damals waren Gedächtnistreffer weniger relevant und Teilungen viel schlimmer. Heutzutage bewerte ich die Lesbarkeit höher, aber wenn es keinen Unterschied in der Lesbarkeit gibt, halte ich es für eine gute Angewohnheit, sich für Multiplikationen zu entscheiden.
quelle
Schreiben Sie, was klarer ist, und geben Sie Ihre Absicht an.
Nachdem Ihr Programm funktioniert hat, finden Sie heraus, was langsam ist, und beschleunigen Sie dies.
Mach es nicht umgekehrt.
quelle
Mach was du brauchst. Denken Sie zuerst an Ihren Leser. Machen Sie sich keine Sorgen um die Leistung, bis Sie sicher sind, dass Sie ein Leistungsproblem haben.
Lassen Sie den Compiler die Leistung für Sie erledigen.
quelle
Wenn Sie mit Ganzzahlen oder Nicht-Gleitkommatypen arbeiten, vergessen Sie nicht Ihre Bitverschiebungsoperatoren: << >>
quelle
Tatsächlich gibt es einen guten Grund dafür, dass die Faustmultiplikation in der Regel schneller ist als die Division. Die Gleitkommadivision in der Hardware erfolgt entweder mit Verschiebungs- und bedingten Subtraktionsalgorithmen ("lange Division" mit Binärzahlen) oder - heutzutage wahrscheinlicher - mit Iterationen wie der von Goldschmidt Algorithmus. Das Verschieben und Subtrahieren erfordert mindestens einen Zyklus pro Bit Genauigkeit (die Iterationen sind nahezu unmöglich zu parallelisieren, ebenso wie das Verschieben und Addieren der Multiplikation), und iterative Algorithmen führen mindestens eine Multiplikation pro Iteration durch oder eher als vernünftig. Die Pedanterie von "Code, was am klarsten ist" ist absolut wahr, aber alle drei sind so gut lesbar, dass die Pedanterie in diesem Fall nur pedantisch ist.. In beiden Fällen ist es sehr wahrscheinlich, dass die Division mehr Zyklen benötigt. Dies berücksichtigt natürlich keine Macken bei Compilern, Datenverschiebungen oder Präzision. Im Großen und Ganzen eine innere Schleife in einem zeitkritischen Teil eines Programms zu codieren schreiben,
0.5 * x
1.0/2.0 * x
x / 2.0
quelle
Ich habe immer gelernt, dass Multiplikation effizienter ist.
quelle
Die Multiplikation ist normalerweise schneller - sicherlich nie langsamer. Wenn es jedoch nicht geschwindigkeitskritisch ist, schreiben Sie, was am klarsten ist.
quelle
Die Gleitkommadivision ist (im Allgemeinen) besonders langsam. Während die Gleitkommamultiplikation ebenfalls relativ langsam ist, ist sie wahrscheinlich schneller als die Gleitkommadivision.
Aber ich bin eher geneigt zu antworten, "es ist nicht wirklich wichtig", es sei denn, die Profilerstellung hat gezeigt, dass Division ein bisschen Engpass gegenüber Multiplikation ist. Ich vermute jedoch, dass die Wahl zwischen Multiplikation und Division keinen großen Einfluss auf die Leistung Ihrer Anwendung haben wird.
quelle
Dies wird eher zu einer Frage, wenn Sie in Assembly oder vielleicht in C programmieren. Ich denke, dass bei den meisten modernen Sprachen eine solche Optimierung für mich durchgeführt wird.
quelle
Seien Sie vorsichtig, wenn Sie davon ausgehen, dass Multiplikation in der Regel besser ist. Deshalb versuche ich, mich beim Codieren daran zu halten.
Im Zusammenhang mit dieser speziellen Frage bedeutet besser hier "schneller". Welches ist nicht sehr nützlich.
Über Geschwindigkeit nachzudenken kann ein schwerwiegender Fehler sein. Die spezifische algebraische Form der Berechnung hat tiefgreifende Auswirkungen auf Fehler.
Siehe Gleitkomma-Arithmetik mit Fehleranalyse . Siehe Grundlegende Probleme bei der Gleitkomma-Arithmetik und Fehleranalyse .
Während einige Gleitkommawerte genau sind, sind die meisten Gleitkommawerte eine Annäherung. Sie sind ein idealer Wert plus ein Fehler. Jede Operation gilt für den Idealwert und den Fehlerwert.
Die größten Probleme ergeben sich aus dem Versuch, zwei nahezu gleiche Zahlen zu manipulieren. Die am weitesten rechts stehenden Bits (die Fehlerbits) dominieren die Ergebnisse.
In diesem Beispiel können Sie sehen, dass die Differenz zwischen nahezu gleichen Zahlen, wenn die Werte kleiner werden, Ergebnisse ungleich Null erzeugt, bei denen die richtige Antwort Null ist.
quelle
Ich habe irgendwo gelesen, dass die Multiplikation in C / C ++ effizienter ist. Keine Ahnung bezüglich interpretierter Sprachen - der Unterschied ist wahrscheinlich aufgrund des anderen Overheads vernachlässigbar.
Es sei denn, es wird zu einem Problem, bleiben Sie bei dem, was wartbarer / lesbarer ist - ich hasse es, wenn Leute mir das sagen, aber es ist so wahr.
quelle
Ich würde die Multiplikation im Allgemeinen vorschlagen, da Sie die Zyklen nicht damit verbringen müssen, sicherzustellen, dass Ihr Divisor nicht 0 ist. Dies gilt natürlich nicht, wenn Ihr Divisor eine Konstante ist.
quelle
Java Android, profiliert auf Samsung GT-S5830
Ergebnisse?
Die Division ist ungefähr 20% schneller als die Multiplikation (!)
quelle
a = i*0.5
, nichta *= 0.5
. So werden die meisten Programmierer die Operationen verwenden.Wie bei den Posts Nr. 24 (Multiplikation ist schneller) und Nr. 30 - aber manchmal sind beide genauso einfach zu verstehen:
~ Ich finde beide genauso einfach zu lesen und muss sie milliardenfach wiederholen. Es ist daher nützlich zu wissen, dass die Multiplikation normalerweise schneller ist.
quelle
Es gibt einen Unterschied, der jedoch vom Compiler abhängig ist. Zuerst habe ich auf vs2003 (c ++) keinen signifikanten Unterschied für Doppeltypen (64-Bit-Gleitkomma) festgestellt. Als ich die Tests jedoch erneut auf vs2010 durchführte, stellte ich einen großen Unterschied fest, bis zu Faktor 4 schneller für Multiplikationen. Wenn man dies aufspürt, scheint es, dass vs2003 und vs2010 unterschiedliche fpu-Codes generieren.
Auf einem Pentium 4, 2,8 GHz, vs2003:
Auf einem Xeon W3530, vs2003:
Auf einem Xeon W3530, vs2010:
Es scheint, dass im Vergleich zu 2003 eine Division in einer Schleife (der Divisor wurde also mehrmals verwendet) in eine Multiplikation mit der Inversen übersetzt wurde. In vs2010 wird diese Optimierung nicht mehr angewendet (ich nehme an, weil es zwischen den beiden Methoden leicht unterschiedliche Ergebnisse gibt). Beachten Sie auch, dass die CPU Divisionen schneller ausführt, sobald Ihr Zähler 0.0 ist. Ich kenne den genauen Algorithmus, der im Chip fest verdrahtet ist, nicht, aber vielleicht ist er zahlenabhängig.
Edit 18-03-2013: die Beobachtung für vs2010
quelle
n/10.0
durch einen Ausdruck des Formulars(n * c1 + n * c2)
. Ich würde erwarten, dass auf den meisten Prozessoren eine Division länger als zwei Multiplikationen und eine Division dauert, und ich glaube, dass die Division durch eine Konstante unter Verwendung der angegebenen Formulierung in allen Fällen zu einem korrekt gerundeten Ergebnis führen kann.Hier ist eine dumme lustige Antwort:
x / 2.0 ist nicht gleichbedeutend mit x * 0,5
Angenommen, Sie haben diese Methode am 22. Oktober 2008 geschrieben.
Jetzt, 10 Jahre später, erfahren Sie, dass Sie diesen Code optimieren können. Auf die Methode wird in Ihrer Anwendung in Hunderten von Formeln verwiesen. Sie ändern es also und erleben eine bemerkenswerte Leistungsverbesserung von 5%.
War es die richtige Entscheidung, den Code zu ändern? In der Mathematik sind die beiden Ausdrücke tatsächlich gleichwertig. In der Informatik gilt das nicht immer. Weitere Informationen finden Sie unter Minimieren der Auswirkungen von Genauigkeitsproblemen . Wenn Ihre berechneten Werte - irgendwann - mit anderen Werten verglichen werden, ändern Sie das Ergebnis von Kantenfällen. Z.B:
Fazit ist; Wenn Sie sich mit einem der beiden zufrieden gegeben haben, bleiben Sie dabei!
quelle
2
und0.5
Zahlen können in IEEE 754 ohne Genauigkeitsverlust exakt dargestellt werden (im Gegensatz zu z. B.0.4
oder0.1
nicht).Wenn wir davon ausgehen, dass eine Add / Subtrack-Operation 1 kostet, dann multiplizieren Sie 5 und teilen Sie die Kosten auf etwa 20.
quelle
Nach einer so langen und interessanten Diskussion hier ist meine Meinung dazu: Es gibt keine endgültige Antwort auf diese Frage. Wie einige Leute betonten , hängt es sowohl von der Hardware (vgl. Piotrk und gast128 ) als auch vom Compiler (vgl. @ Javiers Tests) ab. Wenn die Geschwindigkeit nicht kritisch ist und Ihre Anwendung keine großen Datenmengen in Echtzeit verarbeiten muss, können Sie sich für Klarheit mithilfe einer Division entscheiden. Wenn Verarbeitungsgeschwindigkeit oder Prozessorlast ein Problem darstellen, ist die Multiplikation möglicherweise die sicherste. Wenn Sie nicht genau wissen, auf welcher Plattform Ihre Anwendung bereitgestellt wird, ist der Benchmark bedeutungslos. Und für die Klarheit des Codes würde ein einziger Kommentar die Arbeit erledigen!
quelle
Technisch gibt es keine Division, es gibt nur eine Multiplikation mit inversen Elementen. Zum Beispiel dividieren Sie nie durch 2, sondern multiplizieren mit 0,5.
'Division' - machen wir uns etwas vor, dass es für eine Sekunde existiert - ist immer schwieriger als die Multiplikation, denn um
x
durchy
eine zu 'dividieren', muss zuerst der Werty^{-1}
so berechnet werden , dassy*y^{-1} = 1
dann die Multiplikation durchgeführt wirdx*y^{-1}
. Wenn Sie bereits wissen ,y^{-1}
dann die Berechnung nicht ausy
muss eine Optimierung sein.quelle