Zitat von
3_of_8:
Das sehe ich anders. Bei so grundlegenden, also so eigentlich primitiven Funktionen jedenfalls. Bei einer sehr speziellen Funktion, die selten aufgerufen wird, kann das wieder anders aussehen. Aber wenn mein Code oft wiederverwendet wird, optimiere ich ihn lieber.
Und so ein if kann den Prozessor nunmal ordentlich ausbremsen, daher vermeide ich es nunmal gerne.
@3_of_8 :
Wenn Du schon bei "eigentlich pimitiven" Funktionen lieber optimierst, warum machst Du das denn nicht konsequent ?
Ich hab mal Deinen Vorschlag und zwei Alternativen getestet.
Für jeweils 1000000 Durchläufe habe ich gemessen (P4, 2.66 GHz)
Dein Vorschlag = 38.7 ms
Alternative 1 = 16.1 ms
Alternative 2 = 5.6 ms, also knapp 7 mal so schnell wie Deine Version....
Ich denke, daß ca. sieben mal so schnell eine Assemblerversion rechtfertigt.
Und warum ist Deine Funktion so bummelig ?
Schau Dir das ganze doch mal im Debugger in der CPU-Ansicht an.
Du übergibst 2 Extended Werte als Const Parameter (weil du meints das bringe Vorteile ?). Bringt aber nichts. Es werden nicht etwa Pointer in Registern übergeben sondern die Parameter werden auf dem Stack übergeben.
Tatsächlich passiert in etwa folgendes.
1) a und b werden auf den Stack gelegt. Dann wird Deine Funktion aufgerufen.
2) das "result:=a" legt a dann noch einmal auf den Stack.
3) dann kommt die Berechnung des Vorzeichens, was auch nicht ganz so schnell abläuft.
4) abschließend wird result vom Stack in die FPU geladen. (Extended Werte werden im TOS zurück gegeben.)
5) und wird dann nach Rückkehr aus Deiner Funktion in c gestellt.
Und warum sind die Alternativen so schnell ? Schaue es Dir mal im Debugger an....
Bei allen Versionen ist übrigens, wenn a=0 und b negativ ist, das Resultat -0 (ja, die FPU unterscheidet zwischen positiver 0 und negativer 0). Ob das bei irgenwelchen Berechnungen Auswirkungen hat, ist mir nicht bekannt.
Alternative 1
Delphi-Quellcode:
PROCEDURE xSignMultiply(
var a,b,c:extended);
asm
fld TByte [eax]
test Byte [edx+9],$80
je @1
fchs
@1: fstp TByte [ecx]
end;
Das "if" und der ev. damit verbundene Sprung kostet übrigens so gut wie gar nichts.
Alternative 2
Delphi-Quellcode:
PROCEDURE ySignMultiply(
var a,b,c:extended);
asm
push ebx
mov ebx,[eax]
mov [ecx],ebx
mov ebx,[eax+4]
mov [ecx+4],ebx
mov ax,[eax+8]
mov bx,[edx+8]
and bx,$8000
xor ax,bx
mov [ecx+8],ax
pop ebx
end;
Der Vollständigkeit wegen Dein Vorschlag
Delphi-Quellcode:
function signmultiply(const a, b: Extended): Extended;
begin
result:=a;
PByte(Integer(@result)+9)^:=PByte(Integer(@result)+9)^ xor
(PByte(Integer(@b)+9)^ and (1 shl 7));
end;
Und mit folgender Prozedur hab ich die Zeiten gemessen.
Delphi-Quellcode:
PROCEDURE TMain.Test;
var a,b,c:extended; i:integer; q0,q1,q2,q3:int64; s1,s2,s3:
string;
begin
a:=-200;
b:=-300;
queryperformancecounter(q0);
for i:=1
to 1000000
do c:=SignMultiply(a,b);
queryperformancecounter(q1);
dec(q1,q0);
queryperformancecounter(q0);
for i:=1
to 1000000
do xSignMultiply(a,b,c);
queryperformancecounter(q2);
dec(q2,q0);
queryperformancecounter(q0);
for i:=1
to 1000000
do ySignMultiply(a,b,c);
queryperformancecounter(q3);
dec(q3,q0);
QueryPerformanceFrequency(q0);
str((q1/q0):0:6,s1);
str((q2/q0):0:6,s2);
str((q3/q0):0:6,s3);
ShowMessage(s1+#13+s2+#13+s3);
end;