Code-Beispiel
FBSinCos, eine neue FreeBASIC-Anweisung
Lizenz: | Erster Autor: | Letzte Bearbeitung: |
k. A. | ytwinky | 15.02.2013 |
Das wunderschöne Feuerwerk2008 war der Grund, dieses Programm zu schreiben. Nicht, weil ich volta's Programm verbessern wollte(was sowieso schwer genug ist)..^^
Es geht um ein grundsätzliches Problem, was die meisten Grafik-Programme betrifft:
Die zeitaufwändige Berechnung der Funktionen Sin() und Cos(), die ja immer Double-Werte liefern.
(Das macht sich in Schleifen schon bemerkbar..)
Es wäre einfach, ein Unterprogramm(UP) zu entwickeln, das beide Funktionen berechnet und die Werte zurückgibt, doch die zeitraubende Berechnung der Funktionen bliebe dann ja erhalten..
Glücklicherweise hat der CoProzessor, der in den meisten der heutzutage eingesetzten Rechner vorhanden ist, eine eingebaute Funktion, die genau dies liefert: fsincos
Tolle Wurst, wie geht das denn?
Na, zuerst muß der Winkel(MUSS im Bogenmaß sein) an den CoProzessor übergeben werden, dann wird die Berechnung ausgeführt und fertig..
Ganz so einfach ist es zwar nicht wirklich, aber das folgende Programm zeigt, wie es geht:
'+-----------------------------------------------------------------------------------+
'| Header: Check parameters(if any..) |
'| DisplayCheck:|Il1 are Alt-0124, Big i, small L, One „ä”öüáߎę֚Üñ±¸©ø° |
Const Author="FBSinCos.Bas v018.3b ¸2008 by ytwinky, MD"' |
'| (ShortCuts: none) |
'| Credits: Thx @ volta 4 optimizing the ASM-part ;-)) |
'| Purpose: Evaluate Sin AND Cos with ONE (Asm-)Statement |
'+-----------------------------------------------------------------------------------+
'(For the special chars: the first is the DOS-char, then the Win-char)
Const RhoD=45.0/Atn(1.0)
Dim As Double Angle, fbSin, fbCos
Sub FBSinCos(Angle As Double, byRef fbSin As Double, byRef fbCos As Double)
'©2008 by ytwinky, optimized by volta ;-))
Asm
fld qword Ptr [Angle] 'Angle -> st(0)
fsincos 'compute sin AND cos
mov edx, [fbCos] 'Addr. of fbCos -> EDX
fstp qword Ptr [edx] 'St(0) = cos -> fbCos
mov edx, [fbSin] 'Addr. of fbSin -> EDX
fstp qword Ptr [edx] 'St(0) = sin -> fbSin
End Asm
End Sub
Print Author &!"\nCompute Sin AND Cos with ONE (ASM-)Statement"
Do
Input "Angleø(0 --> End):", Angle
If Angle=0 Then End
Angle/=RhoD
Print "Angle=";
Print Using"####.####";Angle*RhoD
FBSinCos(Angle, fbSin, fbCos)
Print "FBSin=" &fbSin &!"\n Sin=" &Sin(Angle) &!"\nFBCos=" &fbCos
Print " Cos=" &Cos(Angle) &!"\nTest=" &fbCos^2+fbSin^2 &"(MUST be 1)"
Loop
So, das funktioniert ja prächtig ^^
Was bringt das nun oder bringt es überhaupt etwas? Rein von der Überlegung her müßte es schneller sein, nur wie messe ich das? Da war doch noch..
Richtig, mit Counter.Bas läßt sich leicht herausfinden, wie sich der neue Befehl verhält:
#include once "windows.bi"
#include "counter.bas"
#Macro dbl_SinCos(Angle, fbSin, fbCos) 'alle als Double
Asm
fld qword Ptr [Angle] 'Angle -> st(0)
fsincos 'compute sin AND cos
fstp qword Ptr [fbCos]'St(0) = cos -> fbCos
fstp qword Ptr [fbSin]'St(0) = sin -> fbSin
End Asm
#EndMacro
Sub FBSinCos(Angle As Double, byRef fbSin As Double, byRef fbCos As Double)
'©2008 by ytwinky, optimized by volta ;-))
Asm
fld qword Ptr [Angle] 'Angle -> st(0)
fsincos 'compute sin AND cos
mov edx, [fbCos] 'Addr. of fbCos -> EDX
fstp qword Ptr [edx] 'St(0) = cos -> fbCos
mov edx, [fbSin] 'Addr. of fbSin -> EDX
fstp qword Ptr [edx] 'St(0) = sin -> fbSin
End Asm
End Sub
Const sf="######", where=19, LoopCounterValue=100
Dim As Double fbSin, fbCos, Angle=Atn(1.0)/2.0
Print "Statements";Tab(where+1);" cycles"
counter_begin(LoopCounterValue, High_PRIORITY_CLASS)
fbSin = Sin(Angle)
Counter_end
print "Sin(Angle)";:Print Tab(where);:Print Using sf;counter_cycles
counter_begin(LoopCounterValue, High_PRIORITY_CLASS)
fbCos = Cos(Angle)
counter_end
print "Cos(Angle)";:Print Tab(where);:Print Using sf;counter_cycles
counter_begin(LoopCounterValue, High_PRIORITY_CLASS)
fbSin = Sin(Angle)
fbCos = Cos(Angle)
counter_end
print !"\nSin & Cos";:Print Tab(where);:Print Using sf;counter_cycles
counter_begin(LoopCounterValue, High_PRIORITY_CLASS)
FBSinCos(Angle, fbSin, fbCos)
counter_end
print "FBSinCos(Angle)";:Print Tab(where);:Print Using sf;counter_cycles
counter_begin(LoopCounterValue, High_PRIORITY_CLASS)
dbl_SinCos(Angle, fbSin, fbCos)
counter_end
print "dbl_SinCos(Angle)";:Print Tab(where);:Print Using sf;counter_cycles;
GetKey
Der Unterschied ist leider nicht so groß wie ich erhofft hatte, allerdings wird hier auch nur EIN Aufruf ausgewertet. Läuft das Ganze nun in einer großen Schleife sollte ein Geschwindigkeitsgewinn spürbar werden..
So, nun aber wirklich viel Spaß beim FBSinCosen
Gruß
ytwinky
Zusätzliche Informationen und Funktionen |
- Das Code-Beispiel wurde am 01.01.2008 von ytwinky angelegt.
- Die aktuellste Version wurde am 15.02.2013 von Volta gespeichert.
|
|