ho bisogno della funzione di hash più veloce possibile in Delphi 2009 che creerà valori hash da una stringa Unicode che distribuirà abbastanza casualmente in secchi.più efficiente Funzione Unicode hash per Delphi 2009
Originariamente ho iniziato con la funzione HashOf Gabr s' dal GpStringHash:
function HashOf(const key: string): cardinal;
asm
xor edx,edx { result := 0 }
and eax,eax { test if 0 }
jz @End { skip if nil }
mov ecx,[eax-4] { ecx := string length }
jecxz @End { skip if length = 0 }
@loop: { repeat }
rol edx,2 { edx := (edx shl 2) or (edx shr 30)... }
xor dl,[eax] { ... xor Ord(key[eax]) }
inc eax { inc(eax) }
loop @loop { until ecx = 0 }
@End:
mov eax,edx { result := eax }
end; { HashOf }
ma ho scoperto che questo non ha prodotto buoni numeri da stringhe Unicode. Ho notato che le routine di Gabr non sono stati aggiornati a Delphi 2009.
Poi ho scoperto HashNameMBCS in SysUtils di Delphi 2009 e tradotto a questa semplice funzione (dove "stringa" è un Unicode stringa di Delphi 2009):
function HashOf(const key: string): cardinal;
var
I: integer;
begin
Result := 0;
for I := 1 to length(key) do
begin
Result := (Result shl 5) or (Result shr 27);
Result := Result xor Cardinal(key[I]);
end;
end; { HashOf }
ho pensato che questo era abbastanza buono fino a quando ho guardato la finestra di CPU e ho visto il codice assembler ha generato:
Process.pas.1649: Result := 0;
0048DEA8 33DB xor ebx,ebx
Process.pas.1650: for I := 1 to length(key) do begin
0048DEAA 8BC6 mov eax,esi
0048DEAC E89734F7FF call $00401348
0048DEB1 85C0 test eax,eax
0048DEB3 7E1C jle $0048ded1
0048DEB5 BA01000000 mov edx,$00000001
Process.pas.1651: Result := (Result shl 5) or (Result shr 27);
0048DEBA 8BCB mov ecx,ebx
0048DEBC C1E105 shl ecx,$05
0048DEBF C1EB1B shr ebx,$1b
0048DEC2 0BCB or ecx,ebx
0048DEC4 8BD9 mov ebx,ecx
Process.pas.1652: Result := Result xor Cardinal(key[I]);
0048DEC6 0FB74C56FE movzx ecx,[esi+edx*2-$02]
0048DECB 33D9 xor ebx,ecx
Process.pas.1653: end;
0048DECD 42 inc edx
Process.pas.1650: for I := 1 to length(key) do begin
0048DECE 48 dec eax
0048DECF 75E9 jnz $0048deba
Process.pas.1654: end; { HashOf }
0048DED1 8BC3 mov eax,ebx
questo sembra contenere un bel più codice assembler po 'di codice di Gabr.
La velocità è l'essenza. C'è qualcosa che posso fare per migliorare il codice Pascal che ho scritto o l'assemblatore che il mio codice ha generato?
follow-up.
ho finalmente andato con la funzione HashOf sulla base di SysUtils.HashNameMBCS. Sembra dare una buona distribuzione hash per le stringhe Unicode, e sembra essere abbastanza veloce.
Sì, c'è un sacco di codice assembler generato, ma il codice Delphi che genera è così semplice e utilizza solo le operazioni di bit turni, quindi è difficile credere che non sarebbe stato veloce.
Nel tuo HashOf finale dovrei passare da 1 a Lunghezza (tasto). – gabr
@gabr: Grazie. Ora vedo che ho scritto il "followup" senza nemmeno rendermi conto che ho finito per utilizzare la stessa funzione della mia domanda, tranne che ho commesso l'errore nel mio followup. Lo riscriverò. – lkessler