Viel lässt sich da nicht optimieren.
Oh, doch. Die 64bit Div- und Mod-Operationen sind sehr teuer und zudem auch nicht für Divisoren kleiner 2^32 optimiert. Und wenn man dann noch das Div und Mod in einem Schwung ermittelt, kann man da noch einiges rausholen.
Aber auch entfernen der String-Konkatenation tut sein übriges dazu.
Delphi-Quellcode:
function UDivMod6432(
const Dividend: Int64; Divisor: LongWord;
var Rest: LongWord): Int64;
// DivMod64 für "Divisor < 2^32"
{$IFDEF CPUX64}
asm
// in: RCX = Dividend
// EDX = Divisor
// R8 = @Rest
// out: RAX = Quotient
mov rax, rcx
// Register für die Division (RDX:RAX / RCX) vorbereiten
mov ecx, edx
// Divisor in ECX für die Division schieben
xor rdx, rdx
//div ecx // "Divisor < 2^32" ausnutzen
db $F7, $F1
// XE2 compiler bug, es wird immer "div rcx" generiert
mov dword ptr [r8], edx
// Rest in "Rest" schreiben
end;
{$ELSE}
asm
// in: [ebp+$0c]:[ebp+$08] = Dividend
// EAX = Divisor
// EDX = @Rest
// out: EDX:EAX = Quotient
push ebx
push edx
// Zeiger auf Rest sichern
mov ecx, eax
mov eax, dword ptr [ebp+$0c]
// HIGH DWORD des Dividenden als LOW DWORD für die Division laden
xor edx, edx
// kein HIGH DWORD bei der Division
div ecx
// und dividieren (EDX enthält Rest, der als Übertrag genutzt wird)
mov ebx, eax
// HIGH DWORD des Quotienten sichern
mov eax, dword ptr [ebp+$08]
// LOW DWORD des Dividenden laden
div ecx
// und dividieren (EDX enthält Rest)
pop ecx
// Zeiger auf Rest wiederherstellen
mov dword ptr [ecx], edx
// Rest in "Rest" schreiben
mov edx, ebx
// HIGH DWORD des Quotienten wiederherstellen
pop ebx
end;
{$ENDIF CPUX64}
function cvbase_ANSI(n: Int64): AnsiString;
var
Buf:
array[0..7]
of AnsiChar;
Index: Integer;
r: LongWord;
begin
Index := Length(Buf);
while n > 0
do
begin
Dec(
Index);
n := UDivMod6432(n, 255, r);
Buf[
Index] := chtab[r];
end;
SetString(Result, PAnsiChar(@Buf[
Index]), Length(Buf) -
Index);
end;
function cvbase(n: Int64):
string;
var
Buf:
array[0..7]
of Char;
Index: Integer;
r: LongWord;
begin
Index := Length(Buf);
while n > 0
do
begin
Dec(
Index);
n := UDivMod6432(n, 255, r);
Buf[
Index] := chtab[r];
end;
SetString(Result, PChar(@Buf[
Index]), Length(Buf) -
Index);
end;
UPDATE: Die 32bit assembler Version nahm eine falsche Parameterreihenfolge an.