![]() |
Re: Function für Vorzeichen?
Da dürfte Hawkeyes Lösung noch schneller sein.
|
Re: Function für Vorzeichen?
Das ist natürlich möglich. Immerhin braucht Hawks Lösung Pointerberechnung und -inderektion, aber dafür Fließkommavergleiche. Ich weiß nicht aus Erfahrung, was da genau schneller ist - mag das jemand testen? :)
|
Re: Function für Vorzeichen?
Wow, so eine kleine Funktion verursacht so viel geshcreibsel.
Warum schreibt denn nun keiner wie die Funktion richtig aussehen muss?
Delphi-Quellcode:
Wieviel Millisekunden ist dieses "IF" denn langsamer? Oder anders ausgedrückt: Wie oft muss Cöster diese Funktion hintereinander aufrufen, um eine Verzögerung festzustellen? :gruebel:
function Sign(Value: Real): Integer;
begin if Value <= 0 then result := -1 else result := 1; end; |
Re: Function für Vorzeichen?
Zitat:
Danke! |
Re: Function für Vorzeichen?
Halt, ich hab mir deins nochmal angeschaut - das dürfte tatsächlich noch schneller sein.
Deine Lösung funktioniert bei mir nicht. Little Endian Format? Und ich würde es so machen:
Delphi-Quellcode:
function Sign(e: Extended): Integer;
begin result:=0-(PByte(Integer(@e)+9)^ shr 7) or 1; end; |
Re: Function für Vorzeichen?
Moin Dax,
wozu die Pointer?
Delphi-Quellcode:
funktioniert jedenfalls.
function Sign(const AValue : double) : integer;
type TSignHelp = record case boolean of true : (dblValue : double); false : (abDummy : array [1..7] of Byte; bValue : Byte;); end; begin Result := (0 - (TSignHelp(AValue).bValue) shr 7) or 1; end; |
Re: Function für Vorzeichen?
Zitat:
Ne, hab einfach vergessen, das es anders auch geht :duck: |
Re: Function für Vorzeichen?
Meins geht auch ohne großartige Typendeklarationen. :P
|
Re: Function für Vorzeichen?
Zitat:
Delphi-Quellcode:
und fertig?
if b < 0 then a := -a;
Uli. |
Re: Function für Vorzeichen?
Das geht schneller:
Delphi-Quellcode:
c:=signmultiply(a, b) macht in etwa das: if b<0 then c:=-a else c:=a;
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; |
Re: Function für Vorzeichen?
Zitat:
|
Re: Function für Vorzeichen?
Es kommt darauf an, wie oft das aufgerufen wird. Du solltest mal die abs()-Funktion der Math-Unit sehen. Die ist vielleicht optimiert, sag ich dir.
|
Re: Function für Vorzeichen?
Zitat:
greetz Mike |
Re: Function für Vorzeichen?
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. |
Re: Function für Vorzeichen?
Hallo :hi:
hab die Diskussion hier von anfang an verfolgt. Warum? Weils IMHO sehr interessant is, wie man doch so ne einfache Funktion auf unterschiedlichste Art schreiben kann. Aus der ganzen Optimiererei lernt man doch so einiges... Zitat:
Zitat:
In diesem Fall is aber IMHO ne lesbare Version besser. Der Quotent Code-Kommentar / Geschwindigkeit is nämlich annähernd konstant... Und ich hab, wenns auf n paar Mikrosekunden hin oder her nicht ankommt lesbaren code lieber, als schnellen... mfg Christian |
Re: Function für Vorzeichen?
Zitat:
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:
Das "if" und der ev. damit verbundene Sprung kostet übrigens so gut wie gar nichts.
PROCEDURE xSignMultiply(var a,b,c:extended);
asm fld TByte [eax] test Byte [edx+9],$80 je @1 fchs @1: fstp TByte [ecx] end; Alternative 2
Delphi-Quellcode:
Der Vollständigkeit wegen Dein Vorschlag
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;
Delphi-Quellcode:
Und mit folgender Prozedur hab ich die Zeiten gemessen.
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;
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; |
Re: Function für Vorzeichen?
Normalerweise hätte ich das mit Assembler gemacht, aber ich kenne mich dafür noch nicht gut genug mit der FPU aus.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:27 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz