Sin und Cos schneller machen? (SIMPEL)

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

Firstdeathmaker

Betreff: Sin und Cos schneller machen? (SIMPEL)

BeitragMi, Okt 14, 2009 8:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn ihr nicht immer eine so hohe Genauigkeit beim Sinus und Cosinus braucht, und es um ca 60% schneller machen wollt, dann ist folgende Methode vielleicht das Richtige für euch:

Für jedes Grad speichert ihr die Cosinus und Sinus Werte einfach in einem Array. Das bringt zwar im Debugmodus keinen Vorteil, aber bei der finalen Exe Kostet euch ein Aufruf viel weniger Zeit, was sich bei vielen unvermeidbaren Aufrufen rechnet.

SinCosFast.bmx
Code: [AUSKLAPPEN]



Const SINCOSFASTDEGREE:Int = 360
Global SINFASTARR:Float[SINCOSFASTDEGREE]

For Local i:Int = 0 Until SINCOSFASTDEGREE
   SINFASTARR[i] = Sin(i)
Next

Function SinFast:Float(deg:Int)
   Return SINFASTARR[(SINCOSFASTDEGREE + deg Mod SINCOSFASTDEGREE) Mod SINCOSFASTDEGREE]
End Function

Function CosFast:Float(deg:Int)
   deg:+ 90
   Return SINFASTARR[(SINCOSFASTDEGREE + deg Mod SINCOSFASTDEGREE) Mod SINCOSFASTDEGREE]
End Function



Performance Test
Code: [AUSKLAPPEN]

superstrict

Include "SinCosFast.bmx"
Const times:Int = 10000000
Const turns:Int = 10
Global numbers:Float[1000]

For Local i:Int = 0 Until numbers.length
   numbers[i] = Rnd(0,360)
Next


Delay 100


Global time:Int[3]
Global timeglobal:Float[3]


For Local t:Int = 0 Until turns
   time[0] = MilliSecs()
   For Local i:Int = 0 Until times
      Sin(numbers[i Mod numbers.length])
      Cos(numbers[i Mod numbers.length])
   Next
   time[0] = MilliSecs() - time[0]
   
   
   time[1] = MilliSecs()
   For Local i:Int = 0 Until times
      SinFast(numbers[i Mod numbers.length])
      CosFast(numbers[i Mod numbers.length])
   Next
   time[1] = MilliSecs() - time[1]
   
   
   Local a:Float
   time[2] = MilliSecs()
   For Local i:Int = 0 Until times
      a = numbers[i Mod numbers.length]
      a = numbers[i Mod numbers.length]
   Next
   time[2] = MilliSecs() - time[2]
   
   Print "local times"
   Print time[0]
   Print time[1]
   Print time[2]
   
   timeglobal[0]:+ time[0]
   timeglobal[1]:+ time[1]
   timeglobal[2]:+ time[2]
Next


timeglobal[0]:/turns
timeglobal[1]:/turns
timeglobal[2]:/turns

Print "---------------------------------------"
Print "Average for sin cos   : " + timeglobal[0]
Print "Average for sinf cosf : " + timeglobal[1]
Print "Average for just frame: " + timeglobal[2]
Print ""
Print "One Call of Sin + Cos        : "+(1000000 * Float((timeglobal[0] - timeglobal[2])) / times)+"ns"
Print "One Call of SinFast + CosFast: "+(1000000 * Float((timeglobal[1] - timeglobal[2])) / times)+"ns"



Zeiten bei mir (times = 10000000, turns = 10)

NONDEBUG
Average for sin cos : 1461.19995
Average for sinf cosf : 593.299988
Average for just frame: 16.3999996

One Call of Sin + Cos : 144.479996ns
One Call of SinFast + CosFast: 57.6899986ns


DEBUG
Average for sin cos : 2062.60010
Average for sinf cosf : 2317.10010
Average for just frame: 710.799988

One Call of Sin + Cos : 135.180008ns
One Call of SinFast + CosFast: 160.630005ns

"just frame" ist das Framework drumherum, also die Schleifenaufrufe etc. Die Zeit habe ich versucht annähernd zu berechnen, damit man sich die reine Aufrufzeit der Funktionen berechnen kann (zweiter Werteblock).
www.illusion-games.de
Space War 3 | Space Race | Galaxy on Fire | Razoon
Gewinner des BCC #57 User posted image
  • Zuletzt bearbeitet von Firstdeathmaker am Do, Okt 15, 2009 8:36, insgesamt 2-mal bearbeitet

SpionAtom

BeitragMi, Okt 14, 2009 11:40
Antworten mit Zitat
Benutzer-Profile anzeigen
Jun 14, 2004
os: Windows 10 Home cpu: Intel Core i7 6700K 4.00Ghz gpu: NVIDIA GeForce GTX 1080

mpmxyz

BeitragMi, Okt 14, 2009 12:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm... Wo ist der "Performance Test" hin?
Hat der sich versteckt? Wink

Und wenn auch schon "zu große" Winkel beachtet werden, sollten meiner Meinung nach auch negative Winkel bei der Index-Bestimmung berücksichtigt werden, wenn das dann nicht zu langsam ist:
Code: [AUSKLAPPEN]
(SINCOSFASTDEGREE + deg Mod SINCOSFASTDEGREE) Mod SINCOSFASTDEGREE

So bleibt der Index immer in den erlaubten Grenzen.

Wenn 1°-Schritte zu ungenau sind, kann man die Genauigkeit erhöhen, indem man den Code nur noch leicht anpasst.
(SINCOSFASTDEGREE vergrößern und jeden Winkelwert mit einem Faktor von "SINCOSFASTDEGREE/360.0" multiplizieren oder eine Einheit "360°/SINCOSFASTDEGREE" entsprechen lassen)
Aber spätestens dann kann es sich lohnen, zu beachten, dass "Cos(a+90°)=Sin(a)" gilt.
Man braucht dann nur noch eine Wertetabelle.
(Das wurde auch in dem von SpionAtom genannten Thread gesagt)

Sonst habe ich aber nichts dran zu meckern. Wink
Das Vorspeichern von Sinus und Cosinus kann einiges an Geschwindigkeit bringen.
In Blitz3D spare ich ca. 96% der Rechenzeit und habe eine Genauigkeit von 0.001°.
(Ich habe hier leider kein BlitzMax zum Testen)
Wie schnell wäre es, wenn man den Code nach dem "Return" direkt dahin schreiben würde, wo es gebraucht wird?
Es wäre nämlich blöd, wenn die Geschwindigkeit zu sehr durch den Funktionsaufruf verlangsamt wird.

mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer

Firstdeathmaker

BeitragDo, Okt 15, 2009 8:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Habs berichtigt.

@ SpionAtom: Den Thread hab ich nicht gefunden, hatte nur im Codearchiv gesucht, nicht aber in den normalen Threads. Naja, meine Version ist schließlich "ready to use".
www.illusion-games.de
Space War 3 | Space Race | Galaxy on Fire | Razoon
Gewinner des BCC #57 User posted image

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group