Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Anzahl eines Zeichens im String ermitteln (https://www.delphipraxis.net/116372-anzahl-eines-zeichens-im-string-ermitteln.html)

Neutral General 13. Jul 2018 13:58

AW: Anzahl eines Zeichens im String ermitteln
 
Wo zum Henker soll das sein? :shock:
Nein das hilft nicht. Was mir helfen würde wäre vllt. der Inhalt der CPU Register am Anfang meiner Funktion.
Habe das Gefühl dass da wie gesagt etwas nicht so ankommt wie erwartet.

KodeZwerg 13. Jul 2018 14:05

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Neutral General (Beitrag 1407199)
Wo zum Henker soll das sein? :shock:

Delphi-Quellcode:
  mov ecx, len
diese Zeile verursacht bei mir den Fehler.

Neutral General 13. Jul 2018 14:08

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von KodeZwerg (Beitrag 1407200)
Zitat:

Zitat von Neutral General (Beitrag 1407199)
Wo zum Henker soll das sein? :shock:

Delphi-Quellcode:
  mov ecx, len
diese Zeile verursacht bei mir den Fehler.

:?: :?: :?:

Wie zum Teufel kann diese Zeile einen Fehler verursachen?
Zeig mir bitte den die CPU Register direkt nachdem in die Funktion gesprungen wird.
Da ist irgendwas komplett faul..

KodeZwerg 13. Jul 2018 14:10

AW: Anzahl eines Zeichens im String ermitteln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Neutral General (Beitrag 1407199)
Was mir helfen würde wäre vllt. der Inhalt der CPU Register am Anfang meiner Funktion.

Meinst Du das hier Anhang 49504

Uwe Raabe 13. Jul 2018 14:20

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Neutral General (Beitrag 1407194)
Funktioniert diese Version bei euch?

Ja, funktioniert jetzt. Allerdings ist das Zeitverhalten (mit Optimierung) noch schlechter als die Standardfunktion CountChar im StringHelper und damit landet die Lösung in der hiesigen Rangliste auf dem drittletzten Platz. Lediglich die StringReplace-Lösung und die AnsiString-Lösung (vermutlich wegen der bei jedem Aufruf nötigen Umwandlungen) sind noch langsamer.

Hier meine Zeiten für einen Teststring mit 500000 ASCII-Zeichen, Suche nach 'X', jeweils 10000 Calls, Zeiten in Millisekunden:

Zitat:

00000 Calibrate
02292 Uwe Raabe CharCount
02633 KodeZwerg CountCharInString
02953 marabu
03024 Uwe Raabe StringCountCharFor
03046 Egon Hugeist CharCount
03070 Uwe Raabe StringCountChar
03745 Delphi CountChar
03795 alzaimar
03876 Missionar
04028 Neutral General CharCountAsm
05893 Ydobon
06936 KodeZwerg CharInStringA
Eine Kalibrierung des Benchmarks mit einer Fake-Funktion, die aus einem simplen
Delphi-Quellcode:
Result := 0
besteht, brachte erwartungsgemäß 0 ms. Die übrigen Werte schwanken bei wiederholten Aufrufen um weniger als 10%.

Neutral General 13. Jul 2018 14:22

AW: Anzahl eines Zeichens im String ermitteln
 
Ja.
Und der Screenshot ist gemacht worden als das Programm auf dem "cld" Befehl (oder auf "asm") angehalten war?
Weil dann versteh ich nicht was da los ist. Ich komme mir irgendwie verarscht vor.

In den Registern ist absolut keine Spur von irgendeinem der Parameter die übergeben werden sollen.
D.h. wenn überhaupt sind die Parameter auf dem Stack, was aber auch absolut keinen Sinn macht.

Dein EIP sieht auch irgendwie seltsam aus.. Vllt. liegt das auch nur an ASLR (?).

Ich weiß nicht was das Problem ist aber von dem was ich hier sehe kann ich meiner Funktion dafür keine Schuld geben wenn aus welchem Grund auch immer bei euch (dir) kompletter Müll in der Funktion ankommt.

Neutral General 13. Jul 2018 14:23

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1407206)
Ja, funktioniert jetzt. Allerdings ist das Zeitverhalten (mit Optimierung) noch schlechter als die Standardfunktion CountChar im StringHelper [...]

Dann scheint das aber stark systemabhängig zu sein. Bei mir sieht das so aus:

Zitat:

Benchmark: 1234588 miep(Data, 'X')
670 Nanoseconds wasted. (found X = 8031 times)

Benchmark: Ydobon Length(Data)-Length(StringReplace(Data, 'X', '', [rfReplaceAll]))
0 Nanoseconds wasted. (found X = 8031 times)

Benchmark: marabu Occurs(Data, 'X')
747 Nanoseconds wasted. (found X = 8031 times)

Benchmark: Missionar cCount(Data, 'X')
840 Nanoseconds wasted. (found X = 8031 times)

Benchmark: alzaimar IFCount(Data, 'X')
656 Nanoseconds wasted. (found X = 8031 times)

Benchmark: Uwe Raabe StringCountChar(Data, 'X')
654 Nanoseconds wasted. (found X = 8031 times)

Benchmark: KodeZwerg CountCharInString(Data, 'X')
248 Nanoseconds wasted. (found X = 8031 times)

Benchmark: KodeZwerg CharInStringA(Data, 'X')
593 Nanoseconds wasted. (found X = 8031 times)

Benchmark: Uwe Raabe CharCount(Data, 'X')
696 Nanoseconds wasted. (found X = 8031 times)

Benchmark: NeutralGeneral CharCount(Data, 'X')
532 Nanoseconds wasted. (found X = 8031 times)

EgonHugeist 13. Jul 2018 14:30

AW: Anzahl eines Zeichens im String ermitteln
 
Noch ein kleiner:

Scanne von beiden Seiten und halbiere die Loop:

Delphi-Quellcode:
function EH_CharCount4(const S: string; C: Char): Cardinal;
var
  P, PEnd: PChar;
begin
  Result := 0;
  P := Pointer(S);
  if P = nil then Exit;
  PEnd := P + PStrLenInt(NativeUInt(P) - SizeOf(StrLenInt))^-1;
  if PEnd = p //handle single char string
  then Inc(Result, Ord(P^ = C))
  else while P < PEnd do begin
    if P^ = C then
      Inc(Result);
    Inc(P);
    if PEnd >= P then begin
      if PEnd^ = C then
        Inc(Result);
      Dec(PEnd);
    end;
  end;
end;
Wegen der Schwankungen empfehle ich jeden test mind 10x durchzuführen und einen avg zu bilden.

gammatester 13. Jul 2018 14:41

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Neutral General (Beitrag 1407194)
Delphi-Quellcode:
function CharCountAsm(AStr: PChar; AChar: Char; len: Integer): Integer;
label loop_start, loop_ende, ende;
asm
  cld
  // Explizite Zuweisung der Parameter in die Register
  mov edi, AStr
  mov ax, AChar
  mov ecx, len
  xor edx, edx
loop_start:
  repnz scasw
  jcxz loop_ende
  inc edx
  jmp loop_start
loop_ende:
  jnz ende
  inc edx
ende:
  mov result, edx
end;

IMO müsste doch statt jcxz loop_ende die 32-Bit-Version jecxz loop_ende benutzt werden.

Außerdem wird edi nirgends gerettet und wieder hergestellt.

Uwe Raabe 13. Jul 2018 15:04

AW: Anzahl eines Zeichens im String ermitteln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Neutral General (Beitrag 1407210)
Dann scheint das aber stark systemabhängig zu sein.

Wie schon erwähnt, ich halte von Benchmarks mit einem einzigen Testcall nicht viel, auch nicht bei einem noch so langem Teststring. Deswegen habe ich das wie bereits beschrieben abgewandelt (siehe Anhang).

Es ist aber in der Tat so, daß es schon zwischen verschiedenen Compilaten durchaus Unterschiede geben kann, bei denen sich die Reihenfolge mancher Kandidaten vertauscht. Das ist wohl auch davon abhängig, was auf dem System sonst gerade noch so alles passiert. Es ist aber schon ein Trend zu erkennen.

Neutral General 13. Jul 2018 15:06

AW: Anzahl eines Zeichens im String ermitteln
 
Oh Mist du hast Recht. Das ist das Problem :wall:
Bei jcxz springt er je nachdem wo er gerade ist zu früh raus. :roll: :wall:

Danke! Da war ich etwas blind..
Wusste nicht dass man esi/edi sichern muss. Hab grad nachgeguckt und du hast Recht.
Hab die Funktion angepasst:
Delphi-Quellcode:
function CharCountAsm(AStr: PChar; AChar: Char; len: Integer): Integer;
label loop_start, loop_ende, ende;
asm
  push edi
  cld
  mov edi, AStr
  mov ax, AChar
  mov ecx, len
  xor edx, edx
loop_start:
  repnz scasw
  jecxz loop_ende
  inc edx
  jmp loop_start
loop_ende:
  jnz ende
  inc edx
ende:
  mov result, edx
  pop edi
end;

KodeZwerg 13. Jul 2018 15:33

AW: Anzahl eines Zeichens im String ermitteln
 
Mit Post 91 klappt es nun ohne EA. Ich weiß auch nicht wo ich vorhin stecken geblieben bin, tut mir leid für Verwirrung. Bei Bedarf kann ich aktuelle Version mit den zwei neuen Ankömmlingen hochladen.
Die Asm Variante reiht sich bei mir so in etwa wie die AnsiStrScan() Methode ein.
Bei der "von-Vorne-und-Hinten" die EgonHugeist schrieb ist kein merklicher Zugewinn spürbar, habs testhalber mit 500MB paar mal durch, das nimmt sich nichts mit Deiner vorigen Methode.

Was mich total verwirrt ist allerdings das Ydobon/StringReplace Ergebnis bei Uwe, also da hat Tokyo (falls es das war bei Dir) einen gigantischen Schritt vollbracht. Wenn ich diese Variante mit einem halben Megabyte aufrufe kann ich erstmal an Briefkasten Post holen, vielleicht ist es fertig wenn ich wieder da bin. Deshalb habe ich es rauskommentiert.
Mit anderen Worten bei mir hat es bei der Zeitmessung mindestens Deinen Wert * 10000 wenn nicht gar * 1000000. Kein Scherz. Ich kann ja mal mit 50MB ein Kompilat hochladen wo das auch gebencht wird, dann seht ihr was ich meine. (Kann sein das die berechnung morgen erst fertig ist)

EgonHugeist 13. Jul 2018 16:13

AW: Anzahl eines Zeichens im String ermitteln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von KodeZwerg (Beitrag 1407221)
Bei der "von-Vorne-und-Hinten" die EgonHugeist schrieb ist kein merklicher Zugewinn spürbar, habs testhalber mit 500MB paar mal durch, das nimmt sich nichts mit Deiner vorigen Methode.

War auch nicht der Zweck. Es ging um die ursprüngliche Frage un das aufweisen verschiedener Varianten.

Wegen der Performance:
Habe mir Uwes Test mit XE10.2-Starter compiliert und meine 2 weiteren Version hinzugefügt.
Zitat:

Starting Benchmark, please be patient...
KodeZwerg's custom Benchmark - DP CountCharInString Edition
Result := 7982

Calibrate - Target missed: 0 <> 7982
00000 Calibrate
04872 1234588 miep
07772 Ydobon
04088 marabu
05025 Missionar
04432 alzaimar
04273 Uwe Raabe StringCountChar
04059 Uwe Raabe StringCountCharFor
04038 KodeZwerg CountCharInString
09867 KodeZwerg CharInStringA
04543 Neutral General CharCountAsm
04378 Uwe Raabe CharCount
04018 Egon Hugeist CharCount_1
04455 Egon Hugeist CharCount_2
04535 Egon Hugeist CharCount_Double_Sided
04671 Delphi CountChar
Benchmark finished!
2. Run:
Zitat:

Starting Benchmark, please be patient...
KodeZwerg's custom Benchmark - DP CountCharInString Edition
Result := 7982

Calibrate - Target missed: 0 <> 7982
00000 Calibrate
04806 1234588 miep
07723 Ydobon
04048 marabu
05072 Missionar
04646 alzaimar
04277 Uwe Raabe StringCountChar
04317 Uwe Raabe StringCountCharFor
04064 KodeZwerg CountCharInString
10165 KodeZwerg CharInStringA
04541 Neutral General CharCountAsm
04364 Uwe Raabe CharCount
03997 Egon Hugeist CharCount_1
04501 Egon Hugeist CharCount_2
04523 Egon Hugeist CharCount_Double_Sided
04656 Delphi CountChar
Benchmark finished!
@Uwe
kannst du das bestätigen? Mir gehen die 30% Performance-Verlust bei meiner Variante 1 ab. Wo sind sie denn hin? Spielt der Compiler Streiche? Habt ihr andere Ergebnisse?

EgonHugeist 13. Jul 2018 16:32

AW: Anzahl eines Zeichens im String ermitteln
 
Zum Spaß:
Delphi-Quellcode:
function EH_CharCount_4(const S: string; C: Char): Cardinal;
var
  P, PEnd: PChar;
begin
  Result := 0;
  P := Pointer(S);
  if P = nil then Exit;
  PEnd := P + PStrLenInt(NativeUInt(P) - SizeOf(StrLenInt))^-1;
  if PEnd = p //handle single char string
  then Inc(Result, Ord(P^ = C))
  else while P < PEnd do begin
    Inc(Result, Ord(P^ = C));
    Inc(P);
    if PEnd >= P then begin
      Inc(Result, Ord(PEnd^ = C));
      Dec(PEnd);
    end;
  end;
end;
Results mit Uwes test:
(Run 1)
Zitat:

Starting Benchmark, please be patient...
KodeZwerg's custom Benchmark - DP CountCharInString Edition
Result := 7982

Calibrate - Target missed: 0 <> 7982
00000 Calibrate
04905 1234588 miep
08639 Ydobon
04217 marabu
05136 Missionar
04639 alzaimar
04337 Uwe Raabe StringCountChar
04164 Uwe Raabe StringCountCharFor
04061 KodeZwerg CountCharInString
10075 KodeZwerg CharInStringA
04451 Neutral General CharCountAsm
04301 Uwe Raabe CharCount
03949 Egon Hugeist CharCount_1
04398 Egon Hugeist CharCount_2
04485 Egon Hugeist CharCount_Double_Sided
03702 Egon Hugeist CharCount_Double_Sided_2
04578 Delphi CountChar
Benchmark finished!
(Run 2)
Zitat:

Starting Benchmark, please be patient...
KodeZwerg's custom Benchmark - DP CountCharInString Edition
Result := 7982

Calibrate - Target missed: 0 <> 7982
00000 Calibrate
04865 1234588 miep
07914 Ydobon
04114 marabu
05044 Missionar
04479 alzaimar
04317 Uwe Raabe StringCountChar
04125 Uwe Raabe StringCountCharFor
04158 KodeZwerg CountCharInString
10157 KodeZwerg CharInStringA
04583 Neutral General CharCountAsm
04390 Uwe Raabe CharCount
03953 Egon Hugeist CharCount_1
04431 Egon Hugeist CharCount_2
04505 Egon Hugeist CharCount_Double_Sided
03740 Egon Hugeist CharCount_Double_Sided_2
04597 Delphi CountChar
Benchmark finished!

Uwe Raabe 13. Jul 2018 16:51

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von EgonHugeist (Beitrag 1407227)
kannst du das bestätigen? Mir gehen die 30% Performance-Verlust bei meiner Variante 1 ab. Wo sind sie denn hin? Spielt der Compiler Streiche? Habt ihr andere Ergebnisse?

Hier meine Ergebnisse, wobei die korrigierte Assembler-Lösung da schon einfließt. Erklären kann ich mir den Unterschied zwischen EH1 und EH2 aber auch nicht. Der erzeugte Code ist offenbar bei EH1 effizienter.

Zitat:

00000 Calibrate
03536 1234588 miep
05918 Ydobon
02947 marabu
03771 Missionar
03686 alzaimar
03013 Uwe Raabe StringCountChar
03079 Uwe Raabe StringCountCharFor
02607 KodeZwerg CountCharInString
06959 KodeZwerg CharInStringA
04000 Neutral General CharCountAsm
02734 Uwe Raabe CharCount
03120 Egon Hugeist CharCount_1
03675 Egon Hugeist CharCount_2
02814 Egon Hugeist CharCount_Double_Sided
03715 Delphi CountChar

Uwe Raabe 13. Jul 2018 17:10

AW: Anzahl eines Zeichens im String ermitteln
 
Jetzt wird's aber interessant! Hier mal die Laufzeiten für Win64 (die ASM-Funktion fällt da logischerweise raus):
Zitat:

00000 Calibrate
03719 1234588 miep
07360 Ydobon
03548 marabu
04122 Missionar
03711 alzaimar
08399 Uwe Raabe StringCountChar
03597 Uwe Raabe StringCountCharFor
02869 KodeZwerg CountCharInString
07099 KodeZwerg CharInStringA
Neutral General CharCountAsm - Target missed: 0 <> 7982
00000 Neutral General CharCountAsm
02183 Uwe Raabe CharCount
03043 Egon Hugeist CharCount_1
03678 Egon Hugeist CharCount_2
02816 Egon Hugeist CharCount_Double_Sided
04076 Delphi CountChar
Der große Verlierer ist hier erstaunlicherweise StringCountChar
Delphi-Quellcode:
  Result := 0;
  for Ch in S do begin
    Inc(Result, Ord(Ch = C));
  end;
während die normale For-Schleife nicht so stark einbricht
Delphi-Quellcode:
  Result := 0;
  for I := Low(S) to High(S) do begin
    Inc(Result, Ord(S[I] = C));
  end;
Die CharCount scheint allerdings vom 64-Bit Compiler zu profitieren.

EWeiss 13. Jul 2018 17:17

AW: Anzahl eines Zeichens im String ermitteln
 
ich weis jetzt nicht was ihr eigentlich erreichen wollt.
http://www.delphigroups.info/2/ed/443666.html
Google spuckt zig varianten von StrScan aus sollte man die jetzt alle einem Benchmark unterwerfen?

KodeZwerg variante ist die erste..
Anscheinend soll die zweite schneller sein.

gruss

Uwe Raabe 13. Jul 2018 17:21

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von EWeiss (Beitrag 1407237)
ich weis jetzt nicht was ihr eigentlich erreichen wollt.

Gar nichts :-D

EgonHugeist 13. Jul 2018 17:35

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1407238)
Zitat:

Zitat von EWeiss (Beitrag 1407237)
ich weis jetzt nicht was ihr eigentlich erreichen wollt.

Gar nichts :-D

So ist es! Spotrlicher Ehrgeiz, mehr ist das nicht.

Uwe ich hätte 'ne Kiste Wein gewettet, ich gewinne. Zitat: "Again what learned". Hu nicht gewettet, puhh!
Ist wirklich interessant! Sei so fair und füge meine letzte version hinzu, bitte.

Macht XE10.2-Starter(32-Bit) wat anders? Ich glaube es nicht..
Wenn ich über neuere CPU's so nachdenke(die alten sterben alle :-D) -> die Challange geht an dich, congrats! :thumb:

Darf man fragen auf was für einer CPU/OS-Version du da reitest?
Mein 5-6 Jahre alter Laptop wackelt mit 'nem i7-3610QM, 2,3GHZ, 32GB-RAM on W10

Schaut so aus, als ob ich beginnen muß den Profilern zu trauen, während ich immer Profiler war...
Bei dem code, wie geschrieben denk ich nicht mal mehr nach -> thank's 4the lesson!

Gruß, Michael

Uwe Raabe 13. Jul 2018 18:50

AW: Anzahl eines Zeichens im String ermitteln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von EgonHugeist (Beitrag 1407239)
Ist wirklich interessant! Sei so fair und füge meine letzte version hinzu, bitte.

Einmal für Win32:
Zitat:

00000 Calibrate
03567 1234588 miep
05984 Ydobon
02945 marabu
03678 Missionar
03604 alzaimar
03013 Uwe Raabe StringCountChar
02998 Uwe Raabe StringCountCharFor
02687 KodeZwerg CountCharInString
07023 KodeZwerg CharInStringA
04072 Neutral General CharCountAsm
02814 Uwe Raabe CharCount
03057 Egon Hugeist CharCount_1
03751 Egon Hugeist CharCount_2
02899 Egon Hugeist CharCount_Double_Sided_3
02958 Egon Hugeist CharCount_Double_Sided_4
03822 Delphi CountChar
und nochmal für Win64:
Zitat:

00000 Calibrate
03777 1234588 miep
07545 Ydobon
03719 marabu
04292 Missionar
03759 alzaimar
08473 Uwe Raabe StringCountChar
03763 Uwe Raabe StringCountCharFor
02921 KodeZwerg CountCharInString
07238 KodeZwerg CharInStringA
Neutral General CharCountAsm - Target missed: 0 <> 7982
00000 Neutral General CharCountAsm
02201 Uwe Raabe CharCount
03022 Egon Hugeist CharCount_1
03731 Egon Hugeist CharCount_2
02952 Egon Hugeist CharCount_Double_Sided_3
03088 Egon Hugeist CharCount_Double_Sided_4
03780 Delphi CountChar
Zitat:

Zitat von EgonHugeist (Beitrag 1407239)
Macht XE10.2-Starter(32-Bit) wat anders? Ich glaube es nicht..

Nein, das glaube ich auch nicht. Der Compiler sollte derselbe sein.

Zitat:

Zitat von EgonHugeist (Beitrag 1407239)
Darf man fragen auf was für einer CPU/OS-Version du da reitest?

i7-4790 3.6 GHz (auch schon etwas in die Jahre gekommen), 32GB RAM, Win10 x64 1709.

Zitat:

Zitat von EgonHugeist (Beitrag 1407239)
Bei dem code, wie geschrieben denk ich nicht mal mehr nach -> thank's 4the lesson!

Ich würde das jetzt nicht überbewerten. Viel hängt da offenbar von der Tagesform des Compilers ab und bis auf wenige Ausreißer ist das Feld doch recht dicht beisammen.

Für mich habe ich die Erkenntnis mitgenommen, daß ich mit der eingebauten Funktion im StringHelper am besten zurecht komme. Die ist bei akzeptabler Performance überall und für alle Plattformen verfügbar, ohne daß ich jedesmal eine Utility-Unit einbinden muss (und irgendwie im VCS verwalten muss). Da zählen andere Kriterien mehr als ein nur marginaler Performancevorteil.

Anbei noch der letzte Softwarestand.

EgonHugeist 14. Jul 2018 06:15

AW: Anzahl eines Zeichens im String ermitteln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Danke für für den letzten Stand.

Ich denke du hast recht. Simples Ausschlusverfahren:

Ich habe mal mein XE10.2-W32 Compilate (release) angehängt. Wenn deine Version immernoch die schnellste mit der EXE ist, dann ist der Compiler ausgeschlossen und da macht deine Hardware einen guten Job.

Bei mir sehen die Ergebnisse (minimale Schwankungen im >5% ) ziehmlich gleich aus.
YFI:
Zitat:

Calibrate - Target missed: 0 <> 7982
00000 Calibrate
04817 1234588 miep
08310 Ydobon
04108 marabu
05045 Missionar
04449 alzaimar
04252 Uwe Raabe StringCountChar
04068 Uwe Raabe StringCountCharFor
04027 KodeZwerg CountCharInString
10237 KodeZwerg CharInStringA
04517 Neutral General CharCountAsm
04350 Uwe Raabe CharCount
03988 Egon Hugeist CharCount_1
04494 Egon Hugeist CharCount_2
04544 Egon Hugeist CharCount_Double_Sided_3
03775 Egon Hugeist CharCount_Double_Sided_4
04657 Delphi CountChar
Aber ist schon interessant, welche Lösungswege existieren! Der Einzeiler über den RecordHelper hat was, ist jedoch nicht Portabel(eg. alte Compiler oder FPC). Der Einzeiler von Ydobon ist extrem kreativ.
Ich persönlich tendiere immer dazu ein set von function zu sammeln und diese Wiederzubenutzen..

EgonHugeist 14. Jul 2018 09:56

AW: Anzahl eines Zeichens im String ermitteln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Double Post. Hab sind noch zwei:

mit direktem Inc des Boolschen ordinals:
Delphi-Quellcode:
function EH_CharCount_5(const S: string; C: Char): Cardinal;
var
  P, PEnd: PChar;
begin
  Result := 0;
  P := Pointer(S);
  if P = nil then Exit;
  PEnd := P + PStrLenInt(NativeUInt(P) - SizeOf(StrLenInt))^-8;
  while P < PEnd do begin
    //comapre 8 Chars per loop
    //this is a simple technic to reduce the loop.
    Inc(Result, Ord(P^=C));
    Inc(Result, Ord((P+1)^=C));
    Inc(Result, Ord((P+2)^=C));
    Inc(Result, Ord((P+3)^=C));
    Inc(Result, Ord((P+4)^=C));
    Inc(Result, Ord((P+5)^=C));
    Inc(Result, Ord((P+6)^=C));
    Inc(Result, Ord((P+7)^=C));
    Inc(P, 8);
  end;
  Inc(PEnd, 8);
  while P < PEnd do begin
    Inc(Result, Ord(P^=C));
    Inc(P);
  end;
end;
ohne direktem Inc des Boolschen ordinals mit if ? then
Delphi-Quellcode:
function EH_CharCount_6(const S: string; C: Char): Cardinal;
var
  P, PEnd: PChar;
begin
  Result := 0;
  P := Pointer(S);
  if P = nil then Exit;
  PEnd := P + PStrLenInt(NativeUInt(P) - SizeOf(StrLenInt))^-8;
  while P < PEnd do begin
    //comapre 8 Chars per loop
    //this is a simple technic to reduce the loop.
    if P^    = C then Inc(Result);
    if (P+1)^ = C then Inc(Result);
    if (P+2)^ = C then Inc(Result);
    if (P+3)^ = C then Inc(Result);
    if (P+4)^ = C then Inc(Result);
    if (P+5)^ = C then Inc(Result);
    if (P+6)^ = C then Inc(Result);
    if (P+7)^ = C then Inc(Result);
    Inc(P, 8);
  end;
  Inc(PEnd, 8);
  while P < PEnd do begin
    if P^=C then
      Inc(Result);
    Inc(P);
  end;
end;
Dies ist die eine typische Technik um die Loops zu reduzieren. Man kann das noch weiter aufbohren für seeehhhr lange strings.
Bei mir rockt EH_CharCount_5 am schnellsten:
Zitat:

00000 Calibrate
04814 1234588 miep
08272 Ydobon
04056 marabu
05014 Missionar
04429 alzaimar
04238 Uwe Raabe StringCountChar
04067 Uwe Raabe StringCountCharFor
04029 KodeZwerg CountCharInString
10193 KodeZwerg CharInStringA
04606 Neutral General CharCountAsm
04501 Uwe Raabe CharCount
04016 Egon Hugeist CharCount_1
04490 Egon Hugeist CharCount_2
04541 Egon Hugeist CharCount_Double_Sided_3
03771 Egon Hugeist CharCount_Double_Sided_4
03199 Egon Hugeist CharCount_5
03803 Egon Hugeist CharCount_6
04657 Delphi CountChar
Compilat hängt an zum Vergleich.

Uwe Raabe 14. Jul 2018 10:04

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von EgonHugeist (Beitrag 1407253)
Ich habe mal mein XE10.2-W32 Compilate (release) angehängt. Wenn deine Version immernoch die schnellste mit der EXE ist, dann ist der Compiler ausgeschlossen und da macht deine Hardware einen guten Job.

Da scheint es beim Compiler doch noch Unterschiede zu geben, aber auch der Prozessor spielt wohl eine Rolle:

Zitat:

00000 Calibrate
03609 1234588 miep
05863 Ydobon
02910 marabu
03662 Missionar
03607 alzaimar
03121 Uwe Raabe StringCountChar
03025 Uwe Raabe StringCountCharFor
02665 KodeZwerg CountCharInString
11464 KodeZwerg CharInStringA
05983 Neutral General CharCountAsm
03961 Uwe Raabe CharCount
04070 Egon Hugeist CharCount_1
03793 Egon Hugeist CharCount_2
03114 Egon Hugeist CharCount_Double_Sided_3
03126 Egon Hugeist CharCount_Double_Sided_4
03805 Delphi CountChar

Zitat:

Zitat von EgonHugeist (Beitrag 1407257)
Dies ist die eine typische Technik um die Loops zu reduzieren.

... und ein direkter Weg ins Desaster, wenn die Stringlänge nicht durch 8 teilbar ist! Die Bedingung der ersten While-Schleife passt nicht so richtig, oder?

EgonHugeist 14. Jul 2018 10:10

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1407258)
Zitat:

Zitat von EgonHugeist (Beitrag 1407253)
Ich habe mal mein XE10.2-W32 Compilate (release) angehängt. Wenn deine Version immernoch die schnellste mit der EXE ist, dann ist der Compiler ausgeschlossen und da macht deine Hardware einen guten Job.

Da scheint es beim Compiler doch noch Unterschiede zu geben, aber auch der Prozessor spielt wohl eine Rolle:
....

Puff, damit hab ich jetzt nicht wirklich gerechnet. Bezhalt vs. Free..

Zitat:

Zitat von Uwe Raabe (Beitrag 1407258)
Zitat:

Zitat von EgonHugeist (Beitrag 1407257)
Dies ist die eine typische Technik um die Loops zu reduzieren.

... und ein direkter Weg ins Desaster, wenn die Stringlänge nicht durch 8 teilbar ist! Die Bedingung der ersten While-Schleife passt nicht so richtig, oder?

Desaster? Wie teilbar?? Uwe ich teile nix! Ich nehm dem PEnd gleich im Eingang 8 chars weg (Subtraktion) und behalte mir die für die letzte tiny loop vor.. Somit ist das Ergebnis garantiert, oder sieht das jemand anders? Der Code passt, sind jedoch typos drin die behalten werden dürfen :stupid:

Harry Stahl 14. Jul 2018 10:23

AW: Anzahl eines Zeichens im String ermitteln
 
Also ich finde die ganzen Varianten höchst interessant und man erfährt dabei ein wenig, wo typische bottlenecks sitzen.:thumb:

String.CountChar kannte ich nicht, also insofern wieder was nützliches dazugelernt (hatte dafür nur eine eigene Funktion).

Cool wäre auch, eine Funktion zu haben, welche nicht nur die Anzahl der Vorkommen des Chars ermittelt, sondern auch noch deren Position z.B. in einem Array zurück gibt. Das könnte auch noch an verschiedenen Stellen hilfreich sein.

Eine fertige Funktion scheint es da aber nicht zu geben, oder (String.split habe ich gesehen, gibt aber ein Array der Teilstrings zurück, ich wäre aber erst mal nur an den Positionen des gesuchten Chars interessiert)?

Uwe Raabe 14. Jul 2018 10:27

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von EgonHugeist (Beitrag 1407259)
Ich nehm dem PEnd gleich im Eingang 8 chars weg und behalte mir die für die letzte tiny loop vor

OK, ich hatte die -8 bei der Berechnung von PEnd übersehen. Sorry!

Die hiesigen Ergebnisse für Win32:
Zitat:

00000 Calibrate
03574 1234588 miep
05938 Ydobon
03004 marabu
03677 Missionar
03600 alzaimar
02959 Uwe Raabe StringCountChar
02968 Uwe Raabe StringCountCharFor
02704 KodeZwerg CountCharInString
07159 KodeZwerg CharInStringA
03950 Neutral General CharCountAsm
02828 Uwe Raabe CharCount
03164 Egon Hugeist CharCount_1
03819 Egon Hugeist CharCount_2
02956 Egon Hugeist CharCount_3
03005 Egon Hugeist CharCount_4
02297 Egon Hugeist CharCount_5
03501 Egon Hugeist CharCount_6
03737 Delphi CountChar
und für Win64:
Zitat:

00000 Calibrate
03678 1234588 miep
07461 Ydobon
03584 marabu
04310 Missionar
03687 alzaimar
08523 Uwe Raabe StringCountChar
03584 Uwe Raabe StringCountCharFor
02865 KodeZwerg CountCharInString
07506 KodeZwerg CharInStringA
Neutral General CharCountAsm - Target missed: 0 <> 7982
00000 Neutral General CharCountAsm
02181 Uwe Raabe CharCount
03025 Egon Hugeist CharCount_1
03776 Egon Hugeist CharCount_2
02747 Egon Hugeist CharCount_3
03028 Egon Hugeist CharCount_4
02964 Egon Hugeist CharCount_5
03358 Egon Hugeist CharCount_6
03829 Delphi CountChar

Harry Stahl 14. Jul 2018 10:40

AW: Anzahl eines Zeichens im String ermitteln
 
Um es selber nachvollziehen zu können: Wie ist denn

PStrLenInt

definiert?

Uwe Raabe 14. Jul 2018 10:40

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Harry Stahl (Beitrag 1407261)
Eine fertige Funktion scheint es da aber nicht zu geben, oder (String.split habe ich gesehen, gibt aber ein Array der Teilstrings zurück, ich wäre aber erst mal nur an den Positionen des gesuchten Chars interessiert)?

Nein, sowas gibt es bislang noch nicht.

Uwe Raabe 14. Jul 2018 10:42

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Harry Stahl (Beitrag 1407263)
Um es selber nachvollziehen zu können: Wie ist denn

PStrLenInt

definiert?

Steht im Source in einem der Attachments weiter oben.

Delphi-Quellcode:
type
  //zentral deklariert
  PStrLenInt = ^StrLenInt;
  StrLenInt = {$IFDEF FPC}SizeInt{$ELSE}LongInt{$ENDIF};

Harry Stahl 14. Jul 2018 10:49

AW: Anzahl eines Zeichens im String ermitteln
 
OK, Danke Uwe.

Harry Stahl 14. Jul 2018 10:51

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1407264)
Zitat:

Zitat von Harry Stahl (Beitrag 1407261)
Eine fertige Funktion scheint es da aber nicht zu geben, oder (String.split habe ich gesehen, gibt aber ein Array der Teilstrings zurück, ich wäre aber erst mal nur an den Positionen des gesuchten Chars interessiert)?

Nein, sowas gibt es bislang noch nicht.

Schade, dann muss ich mir mal überlegen, wo man das bei einer der hier gezeigten Lösungen am besten noch einbauen könnte. Müsste ja dann wohl eine Art dynamisches Array sein, das die einzelnen Positionen aufnimmt.

EgonHugeist 14. Jul 2018 10:57

AW: Anzahl eines Zeichens im String ermitteln
 
@Uwe,

mir scheint der Compiler kennt die Feder das Autors und meint es gut mit ihm :stupid:

Nungut, W64 kann ich dir und CodeZwerg (warum auch immer) auf deinen Pay-Compiler wohl nicht abgraben!
Beim W32 scheint er nun doch auf deiner Seite fremd zugehen..

@Harry

deine Anregung wäre eine weiter Challange -> neues Thema, jodoch sehr leicht. Dieses Thema hier könnte mann auch noch um eine caseinsensitive Suche aufbohren oder so..


@CodeZwerg, wie schauts mit den Benchmarks auf deiner Seite aus??

Harry Stahl 14. Jul 2018 11:22

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von EgonHugeist (Beitrag 1407268)

@Harry

deine Anregung wäre eine weiter Challange -> neues Thema, jodoch sehr leicht. Dieses Thema hier könnte mann auch noch um eine caseinsensitive Suche aufbohren oder so..

Hast recht, ist schon erledigt (TIntDyArray in der Funktion von Uwe eingebaut, da ich dort immer nur eine Stelle habe, wo der Zähler hochgeht). Aber danke auch an Dich für den Hinweis mit der blockweisen Bearbeitung, da kommen mir Ideen für andere Funktionen (z.B. in der Bitmap-Bearbeitung)...

Uwe Raabe 14. Jul 2018 11:45

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von Harry Stahl (Beitrag 1407269)
TIntDyArray in der Funktion von Uwe eingebaut, da ich dort immer nur eine Stelle habe, wo der Zähler hochgeht

Eventuell ist es effizienter, beim ersten Mal die Anzahl der Vorkommen zu ermitteln, dann das Array auf die passende Größe setzen und im zweiten Durchlauf dann die Positionen einzutragen. Mehrfache SetLength-Aufrufe wären da eher suboptimal.

Alternativ eine TList<Integer> füllen und über ToArray in ein Array umwandeln.

Man kann natürlich auch erstmal das Array mit Length(S) anlegen, wenn Speicher keine Rolle spielt.

KodeZwerg 14. Jul 2018 11:58

AW: Anzahl eines Zeichens im String ermitteln
 
Da ich eure Sourcen nicht kompilieren kann werde ich meinen Eigenen Benchmark erweitern und bald hier vorstellen.
Geplant ist eine GUI mit einstellbarer Datenmenge, Anzahl von Wiederholungen, Einzeltests<>Multitests.
Eine Idee um Schwankungen auszugleichen habe ich auch schon, was haltet ihr davon?
Idee: LastNano und CurrNano hält Zeitwerte des letzten und aktuellen Vorgangs, bei neuem Durchgang wird die Differenz von Last und Curr extrahiert, geteilt und der Restwert zugerechnet/abgezogen (je nach dem). Wäre das legitim um einen guten Durchschnittswert zu erhalten?
Eine "AddPosArray" funktionalität für Harry werde ich bei meiner Lieblingsfunktion von Uwe integrieren.
Von Egon hab ich nur zwei Varianten, ich lade mir den letzten Eurer Sourcen und nehme alles mit rein.

Als Ergebnis wird die Liste als Rangfolge dann angezeigt.

Harry Stahl 14. Jul 2018 13:22

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von KodeZwerg (Beitrag 1407272)

Als Ergebnis wird die Liste als Rangfolge dann angezeigt.

Cool, Danke für die Mühe...:thumb:

jaenicke 14. Jul 2018 19:17

AW: Anzahl eines Zeichens im String ermitteln
 
Die Assemblervariante scheitert unter 64-Bit doch nur an dem Unterschied edi <> rdi. Sprich so funktioniert diese unter beidem:
Delphi-Quellcode:
function CharCountAsm(AStr: PChar; AChar: Char; len: Integer): Integer;
label loop_start, loop_ende, ende;
asm
{$ifdef cpux86}
  push edi
{$else}
  push rdi
{$endif}
  cld
{$ifdef cpux86}
  mov edi, AStr
{$else}
  mov rdi, AStr
{$endif}
  mov ax, AChar
  mov ecx, len
  xor edx, edx
loop_start:
  repnz scasw
  jecxz loop_ende
  inc edx
  jmp loop_start
loop_ende:
  jnz ende
  inc edx
ende:
  mov result, edx
{$ifdef cpux86}
  pop edi
{$else}
  pop rdi
{$endif}
end;
Unter 64-Bit sieht das Ergebnis bei mir dann so aus:
Zitat:

Calibrate - Target missed: 0 <> 7982
00000 Calibrate
07331 1234588 miep
06882 Ydobon
07321 marabu
09920 Missionar
07356 alzaimar
09430 Uwe Raabe StringCountChar
07289 Uwe Raabe StringCountCharFor
02684 KodeZwerg CountCharInString
07353 KodeZwerg CharInStringA
03509 Neutral General CharCountAsm
06809 Uwe Raabe CharCount
10014 Egon Hugeist CharCount_1
06651 Egon Hugeist CharCount_2
05407 Egon Hugeist CharCount_Double_Sided_3
05814 Egon Hugeist CharCount_Double_Sided_4
04472 Delphi CountChar
Benchmark finished!
Da ist die Assemblerversion schon recht schnell.

jbg 14. Jul 2018 20:31

AW: Anzahl eines Zeichens im String ermitteln
 
Dann möchte ich meine schnell zusammengeschrieben Assembler-Rountine auch noch ins Rennen werfen.

Delphi-Quellcode:
function AH_CharCountAsm(const S: string; Ch: Char): Cardinal;
asm
{$IFNDEF CPUX64}
  test eax, eax
  jz @@Empty      // wenn S = '' dann gibt es nichts zu tun

  push ebx
  push esi

  mov esi, eax
  xor eax, eax
  xor ebx, ebx

  // Stringlänge ermitteln
  //mov ecx, DWORD PTR [esi-skew].StrRec.Length
  mov ecx, DWORD PTR [esi-$04]

  // ESI auf das String-Ende zeigen lassen und ECX negieren damit ESI+ECX*2 das erste Zeichen ergibt
  lea esi, [esi+ecx*2]
  neg ecx

@@Loop:
  cmp WORD PTR [esi+ecx*2], dx
  sete bl
  add eax, ebx
  inc ecx
  jnz @@Loop

  pop esi
  pop ebx
@@Empty:
{$ELSE}
  xor rax, rax // Rückgabewert auf 0 setzen

  test rcx, rcx
  jz @@Empty      // wenn S = '' dann gibt es nichts zu tun

  mov r8, rcx
  xor ecx, ecx

  // Stringlänge ermitteln
  //movsxd r9, DWORD PTR [r8-skew].StrRec.Length
  movsxd r9, DWORD PTR [r8-$04]

  // R9 auf das String-Ende zeigen lassen und R9 negieren damit R8+R9*2 das erste Zeichen ergibt
  lea r8, [r8+r9*2]
  neg r9

@@Loop:
  cmp WORD PTR [r8+r9*2], dx
  sete cl
  add eax, ecx
  inc r9
  jnz @@Loop
@@Empty:
{$ENDIF ~CPUX64}
end;

Code:
00000 Calibrate
03237 1234588 miep
05421 Ydobon
02629 marabu
03317 Missionar
03232 alzaimar
02661 Uwe Raabe StringCountChar
02629 Uwe Raabe StringCountCharFor
02144 KodeZwerg CountCharInString
07170 KodeZwerg CharInStringA
03498 Neutral General CharCountAsm
01993 Uwe Raabe CharCount
01772 Andreas Hauladen CharCountAsm *****
02696 Egon Hugeist CharCount_1
03242 Egon Hugeist CharCount_2
02556 Egon Hugeist CharCount_Double_Sided_3
02681 Egon Hugeist CharCount_Double_Sided_4
03318 Delphi CountChar

KodeZwerg 14. Jul 2018 21:06

AW: Anzahl eines Zeichens im String ermitteln
 
Danke für weiteren (ASM) Methoden, werde ich mit einbauen, ich fange jetzt mal an Delphi anzukurbeln, kann sein das morgen erst fertig, ich wills diesmal Gründlich machen und nicht nur huschi-wuschi wie die initial-Version.

@Harry, sag oder PN mir Deine Lieblingsmethode für AddPosArray funktionalität. Da ich nichts Cross-Entwickle fehlt mir da die Erfahrung was klappt und was nicht.

@EWeiss, ich hab das ASM aus einer CodeLib heraus gehabt, ich glaub von den Schweizern (die langsame ASM version) und ich kann mich den anderen nur anschließen, just for fun.

Was mich immer noch bei all Euren Resultaten sowas von vom Hocker haut ist wie schlecht D2009 mit der Ydobon Methode performt.
Wenn ich neue Version hoch habe würde ich gerne mal das Ergebnis da sehen, mit meinem D2009 Kompilat bin ich bei Werten * 100000 oder so alle anderen Ergebnisse sind relativ gleich, kommt halt viel auf Processor-Architektur und dessen Pro-MHz Leistung an (sowie eventuelle Chipsatz-Features?).

jaenicke 14. Jul 2018 22:27

AW: Anzahl eines Zeichens im String ermitteln
 
Zitat:

Zitat von KodeZwerg (Beitrag 1407287)
Was mich immer noch bei all Euren Resultaten sowas von vom Hocker haut ist wie schlecht D2009 mit der Ydobon Methode performt.
Wenn ich neue Version hoch habe würde ich gerne mal das Ergebnis da sehen, mit meinem D2009 Kompilat bin ich bei Werten * 100000 oder so alle anderen Ergebnisse sind relativ gleich, kommt halt viel auf Processor-Architektur und dessen Pro-MHz Leistung an (sowie eventuelle Chipsatz-Features?).

Delphi optimiert zwar immer noch relativ schlecht, aber es ist mit der Zeit an ein paar Stellen schon besser geworden. An erweiterten CPU Features liegt der Unterschied aber nicht. Du kannst ja spaßeshalber einfach mal den generierten Assemblercode von Delphi 2009 mit Delphi 10.2 vergleichen. ;-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:30 Uhr.
Seite 3 von 4     123 4      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz