Seite 1 von 2

Schnellerer ACos() mit Array und Makros

Verfasst: 15.12.2006 12:29
von NicTheQuick
Wieder ein Stück aus meiner RayTracing-Engine, die vielleicht jemand
gebrauchen kann, obwohl es jeder wohl auch selbst hinbekommen würde. :wink:
Das Makro ersetzt die rechenintensive Funktion ACos() durch ein Array mit
vorberechneten Werten mit wählbarer Genauigkeit per Konstante.

Laut meinem Speedtest benötigt die Variante bei 20.000.000 Durchläufen
nur runder 38% der Zeit, die die Original-Funktion benötigt. Sicherlich ist
das von Rechner zu Rechner auch wieder unterschiedlich.

Der Speicherverbrauch des Arrays ist auch enorm, solange man Doubles
einsetzt, aber wird bei grafischen Sachen wohl kaum eine Rolle spielen.

Code: Alles auswählen

;Schnellerer ACos() über Array und Macros gelöst
#RT_Cos2ACos = 20000 ;Genauigkeit (Speicherverbrauch: 20001 * SizeOf(Double) = 160.008 Bytes)
#RT_Cos2ACos2 = #RT_Cos2ACos / 2
Global Dim Cos2ACos.d(#RT_Cos2ACos)
For _ = 0 To #RT_Cos2ACos : Cos2ACos(_) = ACos((_ - #RT_Cos2ACos2) * 1.0 / #RT_Cos2ACos2) :Next
Macro RT_ACos(v)
  Cos2ACos(Int(v * #RT_Cos2ACos2) + #RT_Cos2ACos2)
EndMacro
///Edit:
Hier noch die Version für alle, die die Winkel lieber in DEG haben:

Code: Alles auswählen

;Schnellerer ACos() über Array und Macros gelöst
#RT_Cos2ACos = 20000 ;Genauigkeit (Speicherverbrauch: 20001 * SizeOf(Double) = 160.008 Bytes)
#RT_Cos2ACos2 = #RT_Cos2ACos / 2
Global Dim Cos2ACos.d(#RT_Cos2ACos)
For _ = 0 To #RT_Cos2ACos : Cos2ACos(_) = ACos((_ - #RT_Cos2ACos2) * 1.0 / #RT_Cos2ACos2) * 57.295779513082323 : Next
Macro RT_ACos(v)
  Cos2ACos(Int(v * #RT_Cos2ACos2) + #RT_Cos2ACos2)
EndMacro


Debug ACos(0.123456678) * 57.295779513082323
Debug RT_ACos(0.123456678)

Verfasst: 15.12.2006 12:48
von ts-soft

Code: Alles auswählen

For _
:mrgreen:
Tschuldige, dabei kann ich mir ein Grinsen nicht verkneifen

Verfasst: 15.12.2006 13:04
von NicTheQuick
Ist doch 'ne tolle temporäre Variable, meinst du nicht? :mrgreen:

Verfasst: 15.12.2006 13:11
von DrShrek
NicTheQuick hat geschrieben:Ist doch 'ne tolle temporäre Variable, meinst du nicht? :mrgreen:
Eher makaber ;-)

Verfasst: 15.12.2006 13:58
von #NULL

Code: Alles auswählen

_=3:_+_*_-_/2+_-_<<_&$c:Debug _
:o :lol: ["..singatur zu verschenken, greifen sie zu!" :wink: ]

Verfasst: 15.12.2006 14:11
von ts-soft
Hab aus #NULL seinem Code mal eine wiederverwendbar Procedure
gemacht, kann ins CodeArchiv :mrgreen:

Code: Alles auswählen

Procedure _(_)
  ProcedureReturn _+_*_-_/_+_-_<<_&$c
EndProcedure

; example
Debug _(3)

Verfasst: 15.12.2006 14:16
von #NULL
; description:
; converts unfug into mist

Verfasst: 16.12.2006 00:57
von Friedhelm
Mein spiiiiiiiiiiit forschlag

Code: Alles auswählen

;Schnellerer ACos() über Array und Macros gelöst
#RT_Cos2ACos = 20000 ;Genauigkeit (Speicherverbrauch: 20001 * SizeOf(Double) = 160.008 Bytes)
#RT_Cos2ACos2 = #RT_Cos2ACos / 2
Global Dim Cos2ACos.d(#RT_Cos2ACos)
For _ = 0 To #RT_Cos2ACos : Cos2ACos(_) = ACos((_ - #RT_Cos2ACos2) * 1.0 / #RT_Cos2ACos2) :Next
Macro RT_ACos(v)
  Cos2ACos(Int(v * #RT_Cos2ACos2) + #RT_Cos2ACos2)
EndMacro



; float fast_acos(float val)
; 00254 {
; 00255     float fRoot = sqrt(1.0f-val);
; 00256     float fResult = -0.0187293f;
; 00257     fResult *= val;
; 00258     fResult += 0.0742610f;
; 00259     fResult *= val;
; 00260     fResult -= 0.2121144f;
; 00261     fResult *= val;
; 00262     fResult += 1.5707288f;
; 00263     fResult *= fRoot;
; 00264 
; 00265     Return fResult;
; 00266 }

Macro RT_Fast_ACos(v)
   ((((((-0.0187293  *  v)  +  0.0742610)  *  v) -  0.2121144) *  v) +  1.5707288) * Sqr(1.0-v) 
EndMacro



XX=1000000000
string.s = "Ich bin ein fieser Teststring"

Delay(10)
TestZeit.l  = ElapsedMilliseconds()
For i=1 To XX
  Debug  ACos(0.1) 
Next
Zeit1 = ElapsedMilliseconds()-TestZeit

Delay(10)
TestZeit.l  = ElapsedMilliseconds()
For i=1 To XX
  Debug RT_ACos(0.1)
Next
Zeit2 = ElapsedMilliseconds()-TestZeit

Delay(10)
TestZeit.l  = ElapsedMilliseconds()
For i=1 To XX
 Debug RT_Fast_ACos(0.1)
Next
Zeit3 = ElapsedMilliseconds()-TestZeit

Out.s  = "Es wurden je "+Str( XX)+" Aufrufe gestartet"+#crlf$
Out.s  + "ACos()        : "+Str(Zeit1)+" ms."+#crlf$
Out.s  + "RT_ACos()     : "+Str(Zeit2)+" ms."+#crlf$
Out.s  + "RT_Fast_ACos(): "+Str(Zeit3)+" ms."+#crlf$
SetClipboardText(Out)
MessageRequester("Ergebnis",Out,#PB_MessageRequester_Ok)
 
Mein Ergebnise
Es wurden je 1000000000 Aufrufe gestartet
ACos() : 2860 ms.
RT_ACos() : 3422 ms.
RT_Fast_ACos(): 1828 ms.

Verfasst: 17.12.2006 12:14
von remi_meier
Ich verwende hier zur Zeit diesen Code:

Code: Alles auswählen

; Sinus & Cosinus Tabelle
#SINCOS = 1 << 12
Dim tSin.f(#SINCOS)
Dim tCos.f(#SINCOS)
Define.l z
For z = 0 To #SINCOS
  tSin(z) = Sin(z * 2 * #PI / #SINCOS)
  tCos(z) = Cos(z * 2 * #PI / #SINCOS)
Next
#SINCOS ist der Winkel, bei dem man wieder am Anfang steht, also bei
Grad-Angaben 360°. Er sollte im 2^x Format vorliegen, denn dann kann
man ganz einfach mit
angle & (#SINCOS - 1)
den Winkel "angle" auf den Bereich von 0 - #SINCOS-1 beschränken.

Läuft ganz ordentlich hier :D

Verfasst: 17.12.2006 12:44
von Kaeru Gaman