Konvertieren von std :: string in Großbuchstaben: Hauptleistungsunterschied?

7

Also habe ich mit etwas Code herumgespielt und wollte sehen, welche Methode zur Umwandlung einer std :: string in Großbuchstaben am effizientesten ist. Ich dachte mir, dass die beiden in Bezug auf die Leistung etwas ähnlich sind, aber ich habe mich schrecklich geirrt. Jetzt würde ich gerne herausfinden warum.

Die erste Methode zum Konvertieren der Zeichenfolge funktioniert folgendermaßen: Für jedes Zeichen in der Zeichenfolge (speichern Sie die Länge, iterieren Sie von 0 bis zur Länge), wenn sie zwischen 'a' und 'z' liegt, dann verschieben Sie sie zwischen "A" und "Z" stattdessen.

Die zweite Methode funktioniert wie folgt: Für jedes Zeichen in der Zeichenfolge (beginnend von 0, weiter so, bis wir einen Null-Terminator treffen), wenden Sie die Build in toupper () -Funktion an.

Hier ist der Code:

%Vor%

Die erste Methode ToUpper_Reg benötigte ungefähr <169 Sekunden pro 100 Millionen Iterationen.
Die zweite Methode Toupper_Alt benötigte ungefähr 379 Sekunden pro 100 Millionen Iterationen.

Was gibt's?

Edit: Ich habe die zweite Methode so geändert, dass sie die Zeichenkette wiederholt wie die erste (die Länge zur Seite legt, die Schleife kürzer als die Länge) und zwar etwas schneller, aber immer noch etwa zweimal so langsam.

Edit 2: Danke allen für eure Beiträge! Die Daten, mit denen ich es benutzen werde, sind garantiert, also denke ich, dass ich vorerst bei der ersten Methode bleiben werde. Ich vergesse nicht, dass toupper länderspezifisch ist, wenn / falls ich es brauche.

    
Mr. Llama 29.02.2012, 22:48
quelle

8 Antworten

13

std::toupper verwendet das aktuelle Gebietsschema, um Fallkonvertierungen durchzuführen, was einen Funktionsaufruf beinhaltet und andere Abstraktionen. So wird es natürlich langsamer sein. Aber es funktioniert auch bei Nicht-ASCII-Text.

    
Nicol Bolas 29.02.2012, 22:51
quelle
5

toupper() kann mehr als nur Zeichen im Bereich [a-z] verschieben. Zum einen ist es länderabhängig und kann mehr als nur ASCII verarbeiten.

    
bames53 29.02.2012 22:52
quelle
3

toupper() berücksichtigt das Gebietsschema, so dass es (einige) internationale Zeichen verarbeiten kann und viel komplexer ist, als nur den Zeichenbereich 'a' - 'z' zu behandeln.

    
Timo Geusch 29.02.2012 22:52
quelle
3

Nun, ToUpper_Reg() funktioniert nicht. Zum Beispiel wird mein Name nicht in Großbuchstaben umgewandelt. Das heißt, ToUpper_Alt() funktioniert auch nicht, weil toupper() auf einigen Plattformen einen negativen Wert erhält, d. H. Es erzeugt ein undefiniertes Verhalten (normalerweise einen Absturz), wenn es mit meinem Namen verwendet wird. Dies kann jedoch leicht behoben werden, indem man es richtigerweise so nennt:

%Vor%

Das heißt, die beiden Versionen des Codes sind nicht gleichwertig: die Version onot% toupper() schreibt nicht die Zeichen die ganze Zeit, während die letzte Version ist: sobald alles in Großbuchstaben konvertiert wird, nimmt es immer den gleichen Zweig nach einem Test und macht dann nichts. Vielleicht möchtest du ToUpper_Alt() so ändern, dass es so aussieht und erneut testet:

%Vor%

Ich denke, der Unterschied ist das Schreiben: toupper() tauscht den Vergleich für eine Array-Suche aus. Auf das Gebietsschema wird schnell zugegriffen, und alle toupper() übernehmen den aktuellen Zeiger und greifen auf den Ort bei einem gegebenen Offset zu. Mit Daten im Cache ist das wahrscheinlich genauso schnell wie mit der Verzweigung.

    
Dietmar Kühl 29.02.2012 22:55
quelle
0

Der zweite Aufruf beinhaltet einen Funktionsaufruf. Ein Funktionsaufruf ist eine teure Operation in einer inneren Schleife. toupper verwendet auch Locales, um zu bestimmen, wie das Zeichen geändert werden soll.

Der Fortschritt des Aufrufs ist, dass es Standard ist und unabhängig von der Zeichencodierung auf dem Hostcomputer funktioniert.

Das würde ich sehr empfehlen, die Boost-Funktion zu benutzen:

%Vor%

Es handelt sich um eine Vorlage, die mehr als wahrscheinlich inline ist, jedoch Gebietsschemata enthält. Ich würde es immer noch benutzen.

Ссылка

    
111111 29.02.2012 22:53
quelle
0

Ich nehme an, das liegt daran, dass der zweite eine C-Standardbibliotheksfunktion aufruft, die einerseits nicht inline ist, so dass Sie den Overhead eines Funktionsaufrufs erhalten. Aber noch wichtiger ist, dass diese Funktion viel mehr als nur zwei Vergleiche, zwei Sprünge und zwei ganzzahlige Additionen durchführt. Es führt zusätzliche Überprüfungen des Charakters durch und berücksichtigt das aktuelle Gebietsschema und all das Zeug.

    
Christian Rau 29.02.2012 22:54
quelle
0

std :: toupper verwendet das aktuelle Gebietsschema und der Grund, warum dies langsamer als die C-Funktion ist, ist, dass das aktuelle Gebietsschema von verschiedenen Threads geteilt und geändert werden kann. Daher muss das Gebietsschemaobjekt beim Zugriff gesperrt werden, um sicherzustellen, dass dies nicht geschieht während des Anrufs umgeschaltet. Dies geschieht einmal pro Aufruf von toupper und führt zu einem ziemlich großen Overhead (das Erhalten der Sperre kann je nach Implementierung einen Systemaufruf erfordern). Eine Problemumgehung, wenn Sie die Leistung abrufen und das Gebietsschema respektieren möchten, besteht darin, das Gebietsschemaobjekt zuerst zu erstellen (eine lokale Kopie erstellen) und dann die toupper-Facette auf Ihrer Kopie aufzurufen, sodass Sie nicht für jeden topper-Aufruf sperren müssen. Ein Beispiel finden Sie unter dem folgenden Link.

Ссылка

    
JS. 29.02.2012 23:15
quelle
0

Die Frage wurde bereits beantwortet, aber als Nebenbemerkung, ersetzen Sie die Eingeweide Ihrer Schleife in der ersten Methode mit:

%Vor%

macht es noch schneller. Vielleicht ist mein Compiler nur scheiße.

    
wxffles 01.03.2012 00:30
quelle

Tags und Links