1 Tick schnelleres atan2
Verfasst: 24.12.2021 12:05
Hallo Leute!
folgender Code ist zu simpel um unter Tipps & Tricks gepostet zu werden, und es handelt sich auch nicht direkt um ein Bug, nur indirekt um ein Feature request. Ich habe die atan2 von PureBasic mit der internen von Lua 5.4 DLL (mit PellesC kompiliert) verglichen; Lua ist "viel" schneller, meistens ca. 7-15% in den vorigen Tests. Ich habe also versucht die atan2 nachzuschreiben, wie bei wikipedia angegeben. Das Ergebnis ist ein Tick schneller als die PB interne Procedure. Aber es ist immer noch langsamer als die C atan2 funktion welche Lua intern benutzt. Ich habe das nur auf meiner alten XP Möhre getestet, 32bit. Mit PB 6 beta ist es sogar ein bißchen schneller, aber immer noch ist die pb Funktion etwas langsamer. Ich denke die PB Funktion kann optimiert werden.
Vergleich: C lua (math lib), und 2 implementierungen wmath = obige funktion, und pbmath ist nur die pb atan2 funktion "direkt" gewrappt. Ich habe eine alternative "wmath" lib geschrieben welche memos benutzt um einige Kalkulationen zu beschleunigen, nach außen aber die selben Befehle ausweist wie die original. atan2 ließ sich leider nicht memoizieren, jedenfalls nicht mit meinem Erbsenhirn. Daher erstmal nur so ein Ergebnis. Die Reihenfolge der Überprüfungen ist vermutlich nur etwas anders in PB gestaltet, ich hatte nämlich einmal 100% identische Werte; ich hatte atan2 Varianten die auch langsamer waren als die von PB. Leider weisen die Tests jetzt den "großen" Unterschied nicht wirklich nach, aber ein kleiner Unterschied wird schon zu messen sein:
(siehe weiter unten, neue Ergebnisse nach Bugfix und neuem Test code)
PureBasic Test Code
Update: mit ATan() Approximation + Negativwerte werden geprüft
Die Unterschiede sind minimal, aber im Vergleich dazu ist die C atan2 prozedure welche Lua benutzt doch immer ein wenig schneller. 10-15% Leistungssteigerung sind "nicht der Burner", aber "Kleinvieh macht auch Mist".
Lua Skript zur Vollständigkeit (Update)
Ich würde gerne wissen ob ihr auch meßbare unterschiede habt, besonders Neugierig bin ich ob da unterschiede zwischen den 32/64 bit Versionen von PB auftauchen.
folgender Code ist zu simpel um unter Tipps & Tricks gepostet zu werden, und es handelt sich auch nicht direkt um ein Bug, nur indirekt um ein Feature request. Ich habe die atan2 von PureBasic mit der internen von Lua 5.4 DLL (mit PellesC kompiliert) verglichen; Lua ist "viel" schneller, meistens ca. 7-15% in den vorigen Tests. Ich habe also versucht die atan2 nachzuschreiben, wie bei wikipedia angegeben. Das Ergebnis ist ein Tick schneller als die PB interne Procedure. Aber es ist immer noch langsamer als die C atan2 funktion welche Lua intern benutzt. Ich habe das nur auf meiner alten XP Möhre getestet, 32bit. Mit PB 6 beta ist es sogar ein bißchen schneller, aber immer noch ist die pb Funktion etwas langsamer. Ich denke die PB Funktion kann optimiert werden.
Code: Alles auswählen
#HalfPi = #PI / 2
ProcedureC.d WAtan2(x.d,y.d)
If x>0
ProcedureReturn ATan(y/x)
ElseIf x<0 And y>=0
ProcedureReturn ATan(y/x) + #PI
ElseIf x<0 And y<0
ProcedureReturn ATan(y/x) - #PI
ElseIf x=0 And y>0
ProcedureReturn #HalfPi
ElseIf x=0 And y<0
ProcedureReturn -#HalfPi
EndIf
ProcedureReturn 0
EndProcedure
(siehe weiter unten, neue Ergebnisse nach Bugfix und neuem Test code)
PureBasic Test Code
Update: mit ATan() Approximation + Negativwerte werden geprüft
Code: Alles auswählen
; Faster atan2() procedures
#HalfPi = #PI / 2
ProcedureC.d atan_scalar_approximation(x.d)
; Source:
; https://mazzo.li/posts/vectorized-atan2.html
; inline float atan_scalar_approximation(float x) {
; float a1 = 0.99997726f;
; float a3 = -0.33262347f;
; float a5 = 0.19354346f;
; float a7 = -0.11643287f;
; float a9 = 0.05265332f;
; float a11 = -0.01172120f;
;
; float x_sq = x*x;
; return
; x * (a1 + x_sq * (a3 + x_sq * (a5 + x_sq * (a7 + x_sq * (a9 + x_sq * a11)))));
; }
#a1 = 0.99997726;
#a3 = -0.33262347;
#a5 = 0.19354346;
#a7 = -0.11643287;
#a9 = 0.05265332;
#a11 = -0.01172120;
Protected x_sq.d = x * x
ProcedureReturn x * (#a1 + x_sq * (#a3 + x_sq * (#a5 + x_sq * (#a7 + x_sq * (#a9 + x_sq * #a11)))));
EndProcedure
ProcedureC.d XAtan2(x.d,y.d)
If x>0
ProcedureReturn atan_scalar_approximation(y/x)
ElseIf x<0 And y>=0
ProcedureReturn atan_scalar_approximation(y/x) + #PI
ElseIf x<0 And y<0
ProcedureReturn atan_scalar_approximation(y/x) - #PI
ElseIf x=0 And y>0
ProcedureReturn #HalfPi
ElseIf x=0 And y<0
ProcedureReturn -#HalfPi
EndIf
ProcedureReturn 0
EndProcedure
ProcedureC.d WAtan2(x.d,y.d)
If x>0
ProcedureReturn ATan(y/x)
ElseIf x<0 And y>=0
ProcedureReturn ATan(y/x) + #PI
ElseIf x<0 And y<0
ProcedureReturn ATan(y/x) - #PI
ElseIf x=0 And y>0
ProcedureReturn #HalfPi
ElseIf x=0 And y<0
ProcedureReturn -#HalfPi
EndIf
ProcedureReturn 0
EndProcedure
Define pe,ps, we,ws , xe, xs
Define max = 10000000
Define.d angleresult
Delay(1)
ps = ElapsedMilliseconds()
For i=1 To max Step 1
angleresult = ATan2(Random(10000)-5000,Random(10000)-5000 )
Next
pe =ElapsedMilliseconds()
Delay(1)
ws = ElapsedMilliseconds()
For i=1 To max Step 1
angleresult = WATan2(Random(10000)-5000,Random(10000)-5000 )
Next
we = ElapsedMilliseconds()
Delay(1)
xs = ElapsedMilliseconds()
For i=1 To max Step 1
angleresult = XATan2(Random(10000)-5000,Random(10000)-5000)
Next
xe = ElapsedMilliseconds()
msg$ = "Ergebnis" +#CRLF$
msg$ + "loops: "+Str(max)+#CRLF$
msg$ + "atan2 (PB intern):"+Str(pe-ps)+"ms"+#CRLF$
msg$ + "atan2 (WAtan2):"+Str(we-ws)+"ms"+#CRLF$
msg$ + "atan2 (XAtan2, Approximation):"+Str(xe-xs)+"ms"+#CRLF$
CompilerIf #PB_Compiler_Debugger
msg$+#CRLF$+"Hey, der Debugger ist AN. Das ist Schummelei!"+#CRLF$+"Probiere es bitte ohne Debugger."+#CRLF$
CompilerEndIf
SetClipboardText(msg$)
MessageRequester("Leistungsvergleich",msg$)
Lua Skript zur Vollständigkeit (Update)
Code: Alles auswählen
require "wmath"
require "clock"
require "math"
local max = 10000000
local i
local ms,me
local ws,we
local ps,pe
local xs,xe
local tick = clock.tick
local aatan2 = math.atan2
local watan2 = wmath.atan2
local xatan2 = wmath.atan2_2
local patan2 = wmath.pbatan2
local random = wmath.random
local angleresult
ms = tick()
for i=1,max,1 do
angleresult = aatan2(random(10000)-5000,random(10000)-5000)
end
me = tick()
ws = tick()
for i=1,max,1 do
angleresult = watan2(random(10000)-5000,random(10000)-5000)
end
we = tick()
xs = tick()
for i=1,max,1 do
angleresult = xatan2(random(10000)-5000,random(10000)-5000)
end
xe = tick()
ps = tick()
for i=1,max,1 do
angleresult = patan2(random(10000)-5000,random(10000)-5000)
end
pe = tick()
print("performance","loops:",max)
print("lua math",me-ms,"ms")
print("wmath xatan2 (approximation)",we-ws,"ms")
print("wmath watan2",xe-xs,"ms")
print("wmath pb atan2",pe-ps,"ms")