Page 1 of 2
Fastest way to wrap angle values (ASM)
Posted: Thu Jan 12, 2006 1:16 pm
by Psychophanta
Code updated For 5.20+
Useful asm functions to wrap angle values, signed and unsigned angles results:
Code: Select all
Procedure.f WrapAngle(angle.f); <- wraps a value into [0,2*Pi) fringe
!fldpi; <- now i have pi into st0
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[p.v_angle]; <- now i have angle in st0, 2*pi into st1
!fprem; <- now i have the remainder of angle/(2*pi) division (i.e. angle%(2*pi)) in st0, 2*pi in st1
!fadd st1,st0;<- now i have angle%(2*pi) in st0, 2*pi+angle%(2*pi) into st1
!fldz;<- now i have 0 in st0, angle%(2*pi) in st1, 2*pi+angle%(2*pi) into st2
!fcomip st1; <- compare st0 and st1, and pop the stack, which means i have now angle%(2*pi) in st0, 2*pi+remainder into st1
!fcmovnbe st0,st1; <- transfer st1 to st0 if not below or equal.
!fstp st1; <- store st0 in st1 and pops stack, which means i have now the result in st0
ProcedureReturn; <- return the result with this last pop
EndProcedure
Procedure.f WrapAngleSigned(angle.f); <- wraps a value into [-Pi,Pi] fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[p.v_angle]
!fprem1
!fstp st1
ProcedureReturn
EndProcedure
Procedure.f WrapAngleDeg(angle.f); <- wraps a value into [0,360) fringe
!fild dword[@f] ; <- now i have 360 into st0
!fld dword[p.v_angle]
!fprem
!fadd st1,st0
!fldz
!fcomip st1
!fcmovnbe st0,st1
!fstp st1
ProcedureReturn
!@@:dd 360
EndProcedure
Procedure.f WrapAngleDegSigned(angle.f); <- wraps a value into [-180,180] fringe
!fild dword[@f] ; <- now i have 360 into st0
!fld dword[p.v_angle]
!fprem1
!fstp st1
ProcedureReturn
!@@:dd 360
EndProcedure
;It works in radians.
;Usage examples for degrees:
#DEGTORAD=#PI/180.0:#RADTODEG=180.0/#PI
;
angle.f=45
angleadd.f=-90
angle.f=WrapAngle((angle.f+angleadd.f)*#DEGTORAD)*#RADTODEG
Debug angle
;
angle.f=45
angleadd.f=-90
angle.f=WrapAngleSigned((angle.f+angleadd.f)*#DEGTORAD)*#RADTODEG
Debug angle
EDIT: updated to PB4.0B7
Posted: Thu Jan 12, 2006 1:19 pm
by Comtois
thank you
Posted: Fri Jan 13, 2006 2:57 pm
by Comtois
I am wrong or it is not faster ?
Code: Select all
Procedure.f WrapAngle(f1.f); <- wraps a value into [0,2*Pi) fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[esp]
!fprem1
!ftst ;test to see if modulo <= 0
!fnstsw ax ;transfers FPU status word to ax
!fwait
!sahf ;transfers ah to CPU flags.
!jnc near @f ;if number has a negative value (modulo <= 0) then:
!fadd st0,st1
!@@:fstp st1
EndProcedure
Procedure.f WrapValue(Angle.f)
Angle/360
Angle-Int(Angle)
If Angle<0
ProcedureReturn (Angle+1)*360
Else
ProcedureReturn Angle*360
EndIf
EndProcedure
;It works in radians.
;Usage examples for degrees:
#PI=3.14159265:#DEGTORAD=0.01745329:#RADTODEG=57.2957795
#Max= 1000000
;Premier Test
i.f=0
Tps=ElapsedMilliseconds()
While i < #Max
angleNew.f=WrapAngle(i*#DEGTORAD)*#RADTODEG
;angleNew.f=WrapAngle(i)
i + 0.1
Wend
Total1=ElapsedMilliseconds()-Tps
;
; ;Deuxième test
i.f=0
Tps=ElapsedMilliseconds()
While i < #Max
angleNew.f=WrapValue(i)
i + 0.1
Wend
Total2=ElapsedMilliseconds()-Tps
MessageRequester("Test","WrapAngle = " + Str(Total1) + #LFCR$ + "WrapValue = " + Str(Total2),0)
Posted: Fri Jan 13, 2006 3:29 pm
by Psychophanta
About 344 vs 656 reported here.
I guess you are doing something wrong !
I'll add here a degree versions of both functions, i hope today

Posted: Fri Jan 13, 2006 3:35 pm
by Comtois
Psychophanta wrote:About 344 vs 656 reported here.
I guess you are doing something wrong !
i get
---------------------------
Test
---------------------------
WrapAngle = 875
WrapValue = 516
---------------------------
OK
---------------------------
Nothing wrong for me
Code: Select all
Procedure.f WrapAngle(f1.f); <- wraps a value into [0,2*Pi) fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[esp]
!fprem1
!ftst ;test to see if modulo <= 0
!fnstsw ax ;transfers FPU status word to ax
!fwait
!sahf ;transfers ah to CPU flags.
!jnc near @f ;if number has a negative value (modulo <= 0) then:
!fadd st0,st1
!@@:fstp st1
EndProcedure
Procedure.f WrapValue(Angle.f)
Angle/360
Angle-Int(Angle)
If Angle<0
ProcedureReturn (Angle+1)*360
Else
ProcedureReturn Angle*360
EndIf
EndProcedure
;It works in radians.
;Usage examples for degrees:
#PI=3.14159265:#DEGTORAD=0.01745329:#RADTODEG=57.2957795
#Max= 365
i.f=0
While i < #Max
Debug StrF(WrapAngle(i*#DEGTORAD)*#RADTODEG,3) + " / " + StrF(WrapValue(i),3)
i + 0.1
Wend
I'll add here a degree versions of both functions, i hope today

Hope too

Posted: Fri Jan 13, 2006 4:32 pm
by Pupil
you should disable the debugger around the procedures..
Posted: Fri Jan 13, 2006 5:57 pm
by Psychophanta
Comtois, it is very strange what happens there!
Can you try with these 2 and tell results?
Code: Select all
Procedure.f WrapAngle(angle.f); <- wraps a value into [0,2*Pi) fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[esp]
!fprem1
!ftst ;test to see if modulo <= 0
!fstsw ax ;transfers FPU status word to ax
!sahf ;transfers ah to CPU flags.
!jnc near @f ;if number has a negative value (modulo <= 0) then:
!fadd st0,st1
!@@:fstp st1
EndProcedure
Code: Select all
Procedure.f WrapAngle(angle.f); <- wraps a value into [0,2*Pi) fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[esp]
!fprem1
!fadd st1,st0
!fldz
!fcomip st1
!fcmovnbe st0,st1
!fstp st1
EndProcedure
Here is the ones with parameter in Degrees:
Code: Select all
Procedure.f WrapAngleDeg(angle.f); <- wraps a value into [0,360) fringe
!fild dword[@f] ; <- now i have 360 into st0
!fld dword[esp]
!fprem
!fadd st1,st0
!fldz
!fcomip st1
!fcmovnbe st0,st1
!fstp st1
ProcedureReturn
!@@:dd 360
EndProcedure
Procedure.f WrapAngleDegSigned(angle.f); <- wraps a value into [-180,180] fringe
!fild dword[@f] ; <- now i have 360 into st0
!fld dword[esp]
!fprem1
!fstp st1
ProcedureReturn
!@@:dd 360
EndProcedure
;Usage examples:
;
angle.f=45
angleadd.f=-90
angle.f=WrapAngleDeg(angle.f+angleadd.f)
Debug angle
;
angle.f=45
angleadd.f=-90
angle.f=WrapAngleDegSigned(angle.f+angleadd.f)
Debug angle
Posted: Fri Jan 13, 2006 6:44 pm
by Comtois
here is my test
---------------------------
Test
---------------------------
WrapAngle1 = 891
WrapAngle2 = 890
WrapAngle3 = 875
WrapAngleDeg = 860
WrapValue = 500
---------------------------
OK
---------------------------
Code: Select all
DisableDebugger
Procedure.f WrapAngle1(angle.f); <- wraps a value into [0,2*Pi) fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[esp]
!fprem1
!ftst ;test to see if modulo <= 0
!fstsw ax ;transfers FPU status word to ax
!sahf ;transfers ah to CPU flags.
!jnc near @f ;if number has a negative value (modulo <= 0) then:
!fadd st0,st1
!@@:fstp st1
EndProcedure
Procedure.f WrapAngle2(angle.f); <- wraps a value into [0,2*Pi) fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[esp]
!fprem1
!fadd st1,st0
!fldz
!fcomip st1
!fcmovnbe st0,st1
!fstp st1
EndProcedure
Procedure.f WrapAngle3(f1.f); <- wraps a value into [0,2*Pi) fringe
!fldpi
!fadd st0,st0; <- now i have 2*pi into st0
!fld dword[esp]
!fprem1
!ftst ;test to see if modulo <= 0
!fnstsw ax ;transfers FPU status word to ax
!fwait
!sahf ;transfers ah to CPU flags.
!jnc near @f ;if number has a negative value (modulo <= 0) then:
!fadd st0,st1
!@@:fstp st1
EndProcedure
Procedure.f WrapAngleDeg(angle.f); <- wraps a value into [0,360) fringe
!fild dword[@f] ; <- now i have 360 into st0
!fld dword[esp]
!fprem1
!fadd st1,st0
!fldz
!fcomip st1
!fcmovnbe st0,st1
!fstp st1
ProcedureReturn
!@@:dd 360
EndProcedure
Procedure.f WrapValue(Angle.f)
;Auteur Filperj
Angle/360
Angle-Int(Angle)
If Angle<0
ProcedureReturn (Angle+1)*360
Else
ProcedureReturn Angle*360
EndIf
EndProcedure
;It works in radians.
;Usage examples for degrees:
#PI=3.14159265:#DEGTORAD=0.01745329:#RADTODEG=57.2957795
#Max= 1000000
;1er Test
i.f=0
Tps=ElapsedMilliseconds()
While i < #Max
angleNew.f=WrapAngle1(i*#DEGTORAD)*#RADTODEG
i + 0.1
Wend
Total1=ElapsedMilliseconds()-Tps
;2eme Test
i.f=0
Tps=ElapsedMilliseconds()
While i < #Max
angleNew.f=WrapAngle2(i*#DEGTORAD)*#RADTODEG
i + 0.1
Wend
Total2=ElapsedMilliseconds()-Tps
;3eme Test
i.f=0
Tps=ElapsedMilliseconds()
While i < #Max
angleNew.f=WrapAngle3(i*#DEGTORAD)*#RADTODEG
i + 0.1
Wend
Total3=ElapsedMilliseconds()-Tps
;4eme Test
i.f=0
Tps=ElapsedMilliseconds()
While i < #Max
angleNew.f=WrapAngleDeg(i)
i + 0.1
Wend
Total4=ElapsedMilliseconds()-Tps
;5eme test
i.f=0
Tps=ElapsedMilliseconds()
While i < #Max
angleNew.f=WrapValue(i)
i + 0.1
Wend
Total5=ElapsedMilliseconds()-Tps
MessageRequester("Test","WrapAngle1 = " + Str(Total1) + #LFCR$ + "WrapAngle2 = " + Str(Total2) + #LFCR$ + "WrapAngle3 = " + Str(Total3) + #LFCR$ + "WrapAngleDeg = " + Str(Total4) + #LFCR$ + "WrapValue = " + Str(Total5),0)
Posted: Fri Jan 13, 2006 6:51 pm
by Psychophanta
Just copied, pasted and runned:
Does someone know about this wierd Comtois PC behaviour?
Can't understand

The only thing i can say is that obviously this way is not conclusive for testing speed :roll:
Posted: Fri Jan 13, 2006 7:40 pm
by Comtois
Psychophanta wrote:The only thing i can say is that obviously this way is not conclusive for testing speed :roll:
please post a good test , i will try it

Posted: Fri Jan 13, 2006 7:44 pm
by Psychophanta
Theorycally your test is good. But in the practice there is conclusive that must be something wrong, because these functions are ASM optimized.
Posted: Fri Jan 13, 2006 7:49 pm
by netmaestro
There will be a difference between AMD and Intel processors for this kind of optimized approach.
Posted: Fri Jan 13, 2006 7:51 pm
by Comtois
i asked on french forum , it is faster for AMD user .
I have a Pentium 4 2,66.
http://purebasic.hmt-forum.com/viewtopi ... 1540#41540
Posted: Fri Jan 13, 2006 7:53 pm
by Psychophanta
I have AMD Athlon 64 3000+
However, good news to know PB is so fast
EDIT: 468 344 406 375 688 was the result in a pentium centrino 1.8GHz
NOTE: Since Pentium4 seem to have a speed problem with
fprem1 ASM instruction i replaced it to
fprem only in the unsigned result functions bcoz it works the same, but signed functions must have
fprem1.
Posted: Thu Mar 23, 2006 9:24 am
by dagcrack
Another AMD buddie! yay!
This optimization guide is not bad, but theres others out there:
http://www.website.masmforum.com/mark/index.htm
I really can't stand Intel processors (more likely P4) But oh well, got to support them to produce results as fast as possible... Although people keeps on arguing with me.. "p4 is better".. They just have a bigger cache because their processor is bigger bloated!. You don't gain much with a processor that is so bloated...