@sx2008:
Alles was du schriebst ist absolut korrekt.
In meinem Projekt IBANs
http://www.delphipraxis.net/170138-ibans.html habe das zum Teil realisiert.
Die Prüfung von IBANs ist für alle Länder, soweit mir die Daten zugänglich waren, möglich, allerdings betrifft das nur die "Syntax" der IBANs.
Bei der Erstellung von IBANs (ich habe mich da auf "deutsche" beschränkt, bin ich noch etwas weiter gegangen.
Ich prüfe da nicht nur, ob die BLZ aus 8 und die Kontonummer aus 10 Dezimalziffern besteht, sondern auch,
- ob die BLZ tatsächlich existiert (BLZ-Datei der Deutschen Bundesbank)
- ob die Kontonummer von der der BLZ zugeordneten Prüfmethode als gültig anerkannt wird.
Letzteres ist aber auch nur eingeschränkt aussagefähig, weil die Prüfmethoden nur prüfen, ob die Kontonummer eine Kontonummer der jeweiligen Bank sein könnte, jedoch nicht, ob die Kontonummer wirklich existiert.
Wirklich "lecker" ist die Prüfmethode Nr. 09 - die gibt immer "OK" zurück.
Wie ich schon schrieb, ist die in #5 vorgestellte Funktion meinem IBANs-Projekt entnommen.
Da dort die Korrektheit der BLZ und Kontonummer schon an anderer Stelle erfolgt, habe ich in der Funktion zur Erstellung der IBAN diese Prüfung nicht vorgenommen.
Du schriebst "Wichtig ist, dass man mit dem Optimieren aufhört bevor der Code schlecht lesbar wird."
Ich denke "lesbar" ist eine recht subjektive Angelegenheit.
Als Assembler-Freak ist für mich z.B.
ASM-Code lesbar wie ein Buch, andere sehen das, subjektiv zu Recht, ganz anders.
Nun ja, zum Abschluss:
Ich habe mir den Spaß gemacht, die in #5 stehende CreateGermanIBan noch einmal zu optimieren.
Ergebnis für 10M Durchläufe:
Original : 1965 MS,
ASM-Version 390 MS, also 5 Mal so schnell.
Delphi-Quellcode:
FUNCTION ACreateGermanIban(
const BankCode,Account:
String):
String;
asm
test eax,eax
je @Fail
cmp [eax-4],8
jne @Fail
test edx,edx
je @Fail
cmp [edx-4],10
jne @Fail
push ebx
push edi
push esi
mov ebx,eax
// @BankCode
mov edi,edx
// @Account
mov esi,ecx
// @Result
// SetLength(Result,22)
mov eax,ecx
mov edx,22
call System.@UStrSetLength
// Result[1..4]:='DE00'
mov esi,[esi]
mov [esi],$450044
// 'DE'
mov [esi+4],$300030
// '00'
// Result[5..12]:=BankCode
movdqu xmm0,[ebx]
movdqu [esi+8],xmm0
// Result[13..22]:=Account
movdqu xmm0,[edi]
movdqu [esi+8+16],xmm0
mov eax,[edi+16]
mov [esi+8+16+16],eax
// Prüfziffer errechene
mov ebx,97
// Divisor
xor eax,eax
// ... 9 Zeichen ab BankCode[1]
lea edi,[esi+8+18]
// Hinter Result[13]
mov edx,-9
// 9 Zeichen auswerten
call @GetMod
// ... 8 Zeichen ab Account[2]
add edi,16
// Hinter Result[21]
mov edx,-8
// 8 Zeichen auswerten
call @GetMod
// ... Account[10]
movzx ecx,word[edi]
sub cx,'
0'
lea eax,[eax*4+eax]
lea eax,[eax*2+ecx]
// ... 'DE00'
mov ecx,1000000
mul ecx
add eax,131400
// 'DE00'
div ebx
// CheckSum:=98-Checksum
mov eax,98
sub eax,edx
// Result[3..4]=CheckSum
xor edx,edx
mov bl,10
div bl
or [esi+4],al
or [esi+6],ah
pop esi
pop edi
pop ebx
ret
@GetMod: movzx ecx,word[edi+edx*2]
sub cx,'
0'
lea eax,[eax*4+eax]
lea eax,[eax*2+ecx]
@NoDiv: add edx,1
jl @GetMod
div ebx
mov eax,edx
ret
@Fail: mov eax,ecx
// @Result
call System.@WStrClr
end;