Registriert seit: 17. Nov 2005
Ort: Hamburg
1.077 Beiträge
Delphi XE2 Professional
|
AW: Binärdarstellung einer Zahl mit einer einzigen Stringallokation
26. Mai 2012, 20:22
Wegen Speicher ... macht es doch so wie IntToStr oder Format?
ein array[0..31] of Char
als Puffer auf'm Stack,
dann einmal die Zeichen berechnen und den Puffer befüllen,
gleichzeitig werden die Bits automatisch gezählt
und zum Schluß ein SetString, wo nur einmal Speicher allociert wird.
Wirklich schnell ist das aber auch nicht.
Warum?:
Man schreibt die Daten in den Puffer und das SetStr kopiert sie dann in den String.
Besser ist, die Länge des Strings zu definieren und dann direkt in den String zu schreiben.
Die beiden nachstehenden Routinen machen das alles recht flink.
Die zweite Routine ist deutlich schneller weil bummelige Shifts vermieden werden und weil vorwärts geschrieben wird.
Die Tabelle zeigt für die Werte 0, 2^0..31 von links nach rechts
- den Wert
- benötigte CPU-Takte für gammatesters Routine (#11)
- dto für meine Routine (#9)
- dto für die erste der untenstehenden Routinen
- dto für die zweite der untenstehenden Routinen
Code:
0 238 110 126 126
1 578 110 126 136
2 476 136 136 126
4 526 162 144 144
8 500 186 144 144
16 502 212 152 144
32 510 238 160 152
64 518 262 162 160
128 526 288 162 160
256 534 322 170 170
512 544 340 178 170
1024 552 364 204 178
2048 570 390 194 178
4096 586 408 196 186
8192 594 442 212 186
16384 604 466 212 194
32768 620 484 220 188
65536 628 518 228 204
131072 630 536 230 204
262144 646 562 238 204
524288 730 646 246 204
1048576 738 672 246 204
2097152 740 704 272 212
4194304 756 722 262 220
8388608 782 756 272 220
16777216 790 790 288 228
33554432 806 798 280 228
67108864 806 824 296 228
134217728 832 850 296 238
268435456 850 892 314 246
536870912 884 900 306 246
1073741824 892 926 314 254
2147483648 908 952 322 254
Delphi-Quellcode:
FUNCTION IntToBin3(v:Cardinal): string;
asm
push ebx
push eax // V
push edx // @Result
// Benötigte Länge in EBX
xor ebx,ebx
bsr ebx,eax // Länge-1
lea ebx,[ebx+1] // Länge
// Result löschen
mov eax,edx
call System.@UStrClr
// Kurzfassung von NewUniCodeString
lea eax,[ebx*2+12+2] // Länge*2 + SizeOf(StrRec) + 2
call System.@GetMem
mov edx,DefaultUnicodeCodePage
and edx,$FFFF // nur LoWord
or edx,$20000 // elemSize
mov [eax],edx // StrRec.codePage und .elemSize
mov [eax+4],1 // StrRec.refCnt
mov [eax+8],ebx // StrRec.Length
lea eax,[eax+12] // @NewString
// @NewString in Result stellen
pop edx
mov [edx],eax // Result
// Ende 00 ans Stringende schreiben
lea eax,[eax+ebx*2] // @NewString[Len+1]
mov word [eax],0 // Str-Terminator
// V als Binärstring in Result schreiben
pop edx // V
@Loop: lea eax,[eax-2]
shr edx,1
setc bl
lea ebx,[ebx+$30]
mov [eax],bx
jne @Loop
pop ebx
end;
Delphi-Quellcode:
FUNCTION IntToBin4(v:Cardinal): string;
asm
push ebx
push eax // V
push edx // @Result
// Benötigte Länge in EBX
xor ebx,ebx
bsr ebx,eax // Länge-1
lea ebx,[ebx+1] // Länge
// Result löschen
mov eax,edx
call System.@UStrClr
// Kurzfassung von NewUniCodeString
lea eax,[ebx*2+12+2] // Länge*2 + SizeOf(StrRec) + 2
call System.@GetMem
mov edx,DefaultUnicodeCodePage
and edx,$FFFF // nur LoWord
or edx,$20000 // elemSize
mov [eax],edx // StrRec.codePage und .elemSize
mov [eax+4],1 // StrRec.refCnt
mov [eax+8],ebx // StrRec.Length
lea eax,[eax+12] // @NewString
mov word[eax+ebx*2],0 // Str-Terminator
// @NewString in Result stellen
pop edx
mov [edx],eax // Result
// V als Binärstring in Result schreiben
pop edx // V
lea eax,[eax+ebx*2] // Hinter String
neg ebx
lea ecx,[ebx+32] // ( v so nach links verschieben,
shl edx,cl // Nit 31 steht )
jmp @Entry
@Loop: add edx,edx
@Entry: sets cl // Sign Flag in BL
lea ecx,[ecx+$30] // in Char wandeln
mov [eax+ebx*2],cx // Char ib String schreiben
add ebx,1
jne @Loop // weiter bis edx leer ist
pop ebx
end;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
|