Code: Alles auswählen
;- Cosinus mittels Funktionsreihe und SSE2 (Double-Precision) berechnen
;- Empfohlener Wertebereich: -90° bis +90° (Rad = -1.57079632679 bis +1.57079632679)
;- "Helle" Klaus Helbing, 27.01.2007, PB v4.02
;- Cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! + (x^8)/8! - (x^10)/10! + (x^12)/12! ... hier nicht mehr Glieder
;- Die Grundidee stammt aus dem Flatassembler-Forum
Global Rad.d = 0.987654321 ;sinnvollen Wertebereich s.o.
Global CosPB.d
Global CosSSE.d
;- Benötigt CPU mit SSE2-Unterstützung --------------------
Macro CosSSE2(a,b)
LEA edi,a ;hier Speicher-Adresse von Rad, Rad = x
!movsd xmm0,[edi] ;1 = x 1 = unteres Quad-Word 2 = oberes Quad-Word
!movhpd xmm0,[edi] ;1 und 2 = x
!lea esi,[v_RezFak] ;Anfangs-Speicher-Adresse der reziproken Fakultäten
!movapd xmm1,xmm0 ;XMM1 = XMM0
!mulpd xmm0,xmm1 ;XMM0: 1 = x^2 2 = x^2
!movapd xmm1,xmm0 ;XMM1: 1 = x^2 2 = x^2
!mulsd xmm0,xmm1 ;XMM0: 1 = x^4 2 = x^2
!mulpd xmm1,xmm1 ;XMM1: 1 = x^4 2 = x^4
!movupd xmm3,[esi] ;Anfangsglied XMM3: 1 = 1.0 2 = 0.0
!movapd xmm2,xmm0 ;XMM2 = XMM0
!mov ecx,-16*3 ;3*2 weitere Glieder, also 6 Iterationen (immer paarweise, daher 3 Schleifendurchläufe)
!@@: ;Test-Werte für 1. und 2. Iteration
!movupd xmm4,[esi+64+ecx] ;1 = 0.04166... 2 = -0.5 ;64=(16*3)+16
!mulpd xmm0,xmm4 ;1 = x^4*0.04166... 2 = x^2*-0.5
!addpd xmm3,xmm0 ;1 = 1.0+0.04166... 2 = 0.0-0.5
!mulpd xmm2,xmm1 ;XMM2: 1 = x^8 2 = x^6 ;nach Ende-Test brachte nichts
!movapd xmm0,xmm2 ;XMM0 = XMM2
!add ecx,16
!jnz @r
LEA edi,b ;Rückgabewert-Variable
!movhlps xmm4,xmm3 ;Ergebnis ist die Summe der beiden Quad-Words von XMM3
!addsd xmm4,xmm3
!movsd qword[edi],xmm4
EndMacro
;----------------------------------------------------------
;- Struktur wegen Speicherverwaltung ----------------------
Structure Cosinus
RF1.d
RF2.d
RF3.d
RF4.d
RF5.d
RF6.d
RF7.d
RF8.d
EndStructure
Define.Cosinus RezFak
RezFak\RF1 = 1.0
RezFak\RF2 = 0.0
RezFak\RF3 = 0.041666666666666667 ; 1/4!
RezFak\RF4 = -0.5 ;-1/2!
RezFak\RF5 = 2.480158730158730159e-5 ; 1/8!
RezFak\RF6 = -0.001388888888888889 ;-1/6!
RezFak\RF7 = 2.087675698786809898e-9 ; 1/12!
RezFak\RF8 = -2.755731922398589065e-7 ;-1/10!
;----------------------------------------------------------
;- Test SSE2
T1= ElapsedMilliseconds()
For i = 0 To 99999999
CosSSE2(Rad, CosSSE) ;Variablen freier Wahl
Next
T1 = ElapsedMilliseconds() - T1
;- Test PB
T2= ElapsedMilliseconds()
For i = 0 To 99999999
CosPB = Cos(Rad)
Next
T2 = ElapsedMilliseconds() - T2
Cos$ = StrD(CosSSE) + " - SSE2 - " + Str(T1) + " ms" + #CRLF$
Cos$ + StrD(CosPB) + " - PB - " + Str(T2) + " ms" + #CRLF$
MessageRequester("Cosinus Double-Precision", Cos$)
End
Helle
Edit: Sprungadresse anonymisiert