Seite 2 von 3

Re: Float als ProcedureReturn Wert

Verfasst: 22.01.2010 16:03
von STARGÅTE
Ich glaube dieses Ergebnis ist mehr als Deutlich:

Code: Alles auswählen

B.f = 5
C.f = 0.2

time = ElapsedMilliseconds()
For n = 1 To 10000000
 A.f = 1/B/B/B/B 
Next
time1 = ElapsedMilliseconds()-time
time = ElapsedMilliseconds()
For n = 1 To 10000000
 A.f = 1*C*C*C*C 
Next
time2 = ElapsedMilliseconds()-time
MessageRequester("", Str(time1)+" zu "+Str(time2))
---------------------------

---------------------------
2093 zu 157
---------------------------
OK
---------------------------
Multiplikation ist mehr als 10 mal schneller als Division ...
natürlich ohne Debugger

Re: Float als ProcedureReturn Wert

Verfasst: 22.01.2010 16:04
von freak
Kaeru Gaman hat geschrieben:
es geht um das Multiplizieren, statt Dividieren !
interessant... worauf basierst du diese Aussage?
FMUL Instruktion: 5 Clock Cycles
FDIV Instruktion: 30 Clock Cycles (single precision)

Genaue Daten variieren je nach Prozessortyp.
Quelle: http://www.intel.com/Assets/PDF/manual/248966.pdf

Re: Float als ProcedureReturn Wert

Verfasst: 22.01.2010 16:07
von ts-soft
@freak
danke für den Hinweis, hab mir schon gedacht das malnehmen schneller ist.

<offtopic>Ich frag mich sowieso, warum die Rechengenauigkeit eines "ts-soft" höher als die eines modernen PCs ist :mrgreen: </offtopic>

Re: Float als ProcedureReturn Wert

Verfasst: 22.01.2010 16:12
von freak
Es sollte übrigens angemerkt werden das FSIN mit 160-200 Cycles hier dann doch überwiegen wird, egal ob mit Multiplikation oder Division. Wenn man also wirklich derart auf Geschwindigkeit aus ist lohnt es sich einen Lookup-Table in Betracht zu ziehen :wink:

Re: Float als ProcedureReturn Wert

Verfasst: 22.01.2010 17:44
von Josh
STARGÅTE hat geschrieben:---------------------------

---------------------------
2093 zu 157
---------------------------
OK
---------------------------
ich hab hier nur eine alte kiste stehn, komm aber auf ganz andere ergebnisse

2297 zu 1750

also weit weg von dem 10 fachen

Re: Float als ProcedureReturn Wert

Verfasst: 22.01.2010 17:53
von Kaeru Gaman
freak hat geschrieben:FMUL Instruktion: 5 Clock Cycles
FDIV Instruktion: 30 Clock Cycles (single precision)

Genaue Daten variieren je nach Prozessortyp.
Quelle: http://www.intel.com/Assets/PDF/manual/248966.pdf
klasse, danke! :D
freak hat geschrieben:Es sollte übrigens angemerkt werden das FSIN mit 160-200 Cycles hier dann doch überwiegen wird, egal ob mit Multiplikation oder Division. Wenn man also wirklich derart auf Geschwindigkeit aus ist lohnt es sich einen Lookup-Table in Betracht zu ziehen :wink:
völlig richtig!
http://www.purebasic.fr/german/viewtopic.php?t=5884

Re: Float als ProcedureReturn Wert

Verfasst: 22.01.2010 23:22
von Helle
Eine Lookup-Table ist natürlich speed-mäßig unschlagbar, das Problem dürfte aber immer das Verhältnis Genauigkeit (Auflösung ) - Table-Größe sein. Wenn für eine Sinus-Berechnung der Radiant so im Bereich zwischen -Pi/2 und +Pi/2 liegt, kann auch Folgendes mal getestet werden (eine CPU mit SSE-Unterstützung setze ich mal voraus):

Code: Alles auswählen

;- Sinus-Berechnung (Single-Precision) mit SSE im Bereich -90° bis +90°
;- Verwendet wird die Reihenentwicklung Sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! + (x^9)/9!...
;- die Glieder 2-5 können in einem SSE-Register berechnet werden (1 Float-Wert = 32-Bit, 1 SSE-Register = 128-Bit)
;- "Helle" Klaus Helbing, 22.01.2010, PB v4.40 x86, Windows32

Global Radiant.f = 0.987654            ;hier Testwert, je nach erforderlicher Genauigkeit Werte zwischen -Pi/2 und +Pi/2 sinnvoll; testen!
Global SinPB.f
Global SinSSE.f

Procedure SinSSE(Radiant, SinSSE)      ;oder Parameter (auch Anzahl!) anpassen an eigenes Programm, hier eigentlich doppelt gemoppelt 
  !lea eax,[v_Radiant]                 ;Speicher-Adresse von Radiant 
  !movss xmm0,[eax]                    ;1 = x; 1 = unterstes Double-Word des XMM-Registers, 2 = 2.Double-Word usw.
  !shufps xmm0,xmm0,0                  ;1 - 4 = x
  !movaps xmm2,xmm0                    ;x sichern (1.Glied)
  !movaps xmm1,xmm0
  !mulss xmm1,xmm1                     ;1-1-1-2   Exponenten-Belegung des Zielregisters
  !mulps xmm0,xmm0                     ;2-2-2-2
  !mulps xmm0,xmm1                     ;3-3-3-4
  !movlhps xmm0,xmm1                   ;1-2-3-4
  !mulps xmm0,xmm0                     ;2-4-6-8   
  !mulps xmm0,xmm2                     ;3-5-7-9   also oberstes Double-Word = x^3, unterstes = x^9
  !lea edx,[v_RezFak]                  ;Anfangs-Speicher-Adresse der reziproken Fakultäten  
  !movups xmm1,[edx]
  !mulps xmm0,xmm1                     ;Multiplikation der 4 Power-Werte mit den reziproken Fakultäten
  !movaps xmm1,xmm0
  !shufps xmm1,xmm1,11100101b          ;die einzelnen Glieder in unterstes Double-Word des SSE-Registers schieben
  !addss xmm0,xmm1                     ;und addieren (HADDPS in SSE3)
  !shufps xmm1,xmm1,11100110b  
  !addss xmm0,xmm1   
  !shufps xmm1,xmm1,11100111b 
  !addss xmm0,xmm1   
  !addss xmm0,xmm2                     ;zum Schluss 1.Glied addieren (x)
  !lea eax,[v_SinSSE]
  !movss [eax],xmm0                    ;im untersten DWord von XMM0 steht nun das Ergebnis
EndProcedure
;----------------------------------------------------------

;- Structure für SSE --------------------------------------
Structure Sinus 
  RF1.f : RF2.f : RF3.f : RF4.f 
EndStructure

Define.Sinus RezFak
RezFak\RF1  =  2.755731922398589065e-6 ; 1/9!
RezFak\RF2  = -1.984126984126984127e-4 ;-1/7!
RezFak\RF3  =  8.333333333333333333e-3 ; 1/5!
RezFak\RF4  = -1.666666666666666667e-1 ;-1/3!
;----------------------------------------------------------

;- Test SSE
T1= ElapsedMilliseconds() 
For i = 0 To 19999999 
  SinSSE(Radiant, SinSSE)
Next 
T1 = ElapsedMilliseconds() - T1 

;- Test PB
T2= ElapsedMilliseconds() 
For i = 0 To 19999999 
  SinPB = Sin(Radiant) 
Next 
T2 = ElapsedMilliseconds() - T2 

Sin$ = "Test für Radiant = " + StrF(Radiant) + #CRLF$ + #CRLF$
Sin$ + "SSE : " + StrF(SinSSE) + "  in " + Str(T1) + " ms" + #CRLF$ 
Sin$ + "PB   : " + StrF(SinPB) + "  in " + Str(T2) + " ms" + #CRLF$ 
MessageRequester("Sinus Single-Precision", Sin$)
Soll nur eine Anregung sein :mrgreen: !
Schreibt man ein Programm nur mit Single-Precision und vielen Divisionen (nicht jede Division lässt sich leicht durch eine Multiplikation ersetzen) , kann auch Folgendes ausprobiert werden:

Code: Alles auswählen

B.f = 5
C.f = 0.2

;- althergebracht
time = ElapsedMilliseconds()
For n = 1 To 10000000
  A1.f = 1/B/B/B/B
Next
time1 = ElapsedMilliseconds()-time
time = ElapsedMilliseconds()
For n = 1 To 10000000
  A2.f = 1*C*C*C*C
Next
time2 = ElapsedMilliseconds()-time
;MessageRequester("", Str(time1)+" zu "+Str(time2)+#CRLF$+StrF(A1)+" zu "+StrF(A2))

;- und hier der Test mit zwangsweisem Single-Precision-Test 
Global CWO.w                 ;Originales Control-Word
Global CWN.w                 ;Neues Control-Word

Procedure SetSingleFloat()
  !fstcw [v_CWO]             ;Original Control-Word sichern
  !mov ax,[v_CWO]
  !and ax,1111110011111111b  ;die 2 Precisions-Bits auf Null setzen = Single-Float
  !mov [v_CWN],ax
  !fldcw [v_CWN]             ;das neue Control-Word zurückschreiben
EndProcedure

Procedure RestoreCW()
  !fldcw [v_CWO]             ;das originale Control-Word wieder zurückschreiben
EndProcedure

time = ElapsedMilliseconds()
SetSingleFloat()
For n = 1 To 10000000
  A3.f = 1/B/B/B/B
Next
time3 = ElapsedMilliseconds()-time
time = ElapsedMilliseconds()
For n = 1 To 10000000
  A4.f = 1*C*C*C*C
Next
RestoreCW()
time4 = ElapsedMilliseconds()-time 
MessageRequester("", "Althergebracht: "+Str(time1)+" zu "+Str(time2)+"    " + StrF(A1)+" zu "+StrF(A2)+#CRLF$+"Test:                   "+Str(time3)+" zu "+Str(time4)+"    " + StrF(A3)+" zu "+StrF(A4))
Dies orientiert sich an obigem Beispiel und soll auch nur für Testzwecke (nicht nur Divisionen) sein!
Gruß
Helle

Re: Float als ProcedureReturn Wert

Verfasst: 23.01.2010 11:37
von DerMeister
Danke für die zahlreichen Antworten.
Aber ich muss sagen, ich hab in der Hilfe nachgeschaut, ich hab nur übersehen dass man an die Procedure den Typ des Rückgabewerts anhängen muss.

Re: Float als ProcedureReturn Wert

Verfasst: 23.01.2010 23:26
von hörmi
habs auch mal ausprobiert
766 zu 47 (ohne debugger)
2579 zu 1843 (mit debugger)
schon interessant mal zu sehen wie sich eine fast gleiche rechenoperation auf die performance auswirken kann

Re: Float als ProcedureReturn Wert

Verfasst: 23.01.2010 23:44
von Thorium
Josh hat geschrieben: ich hab hier nur eine alte kiste stehn, komm aber auf ganz andere ergebnisse

2297 zu 1750

also weit weg von dem 10 fachen
Wie du schon geschrieben hast, liegt es an der alten Kiste. Von CPU-Typ zu CPU-Typ variiert wie viele Zyklen bestimmte Instruktionen benötigen.