Limit(), Wrap()
Posted: Fri Oct 31, 2003 12:08 pm
These Limit() and LimitF() are wanted functions when working with plane or spaces, etc.
It is to avoid things like:
These (Wrap() and WrapF()) are to wrap a variable inside a fringe delimited by 2 values:
It is to avoid things like:
Code: Select all
if j>800:j=800:endif
if j<10:j=10:endif
Code: Select all
;Format: Limit(value,margin1,margin2)
Procedure.l Limit(number.l,margin1.l,margin2.l)
!mov ecx,dword[esp] ;number
!mov eax,dword[esp+4] ;margin1
!mov ebx,dword[esp+8] ;margin2
!cmp eax,ebx
!jl near @f ;if margin1 lower than margin2 jump
!xchg eax,ebx ;swap them
!@@: ;now lower margin is in eax, and higher in ebx
!cmp eax,ecx ;if eax (lower margin) > number, then:
!jnl near Limitgo ;return eax (lower margin)
!mov eax,ebx ;load higher margin to eax
!cmp eax,ecx ;if eax (higher margin) < number, then:
!jl near Limitgo ;return eax (higher margin)
!mov eax,ecx ;else return number
!Limitgo:
ProcedureReturn
EndProcedure
;Prove it:
For limit=-20 To 20
Debug Str(limit)+" "+Str(Limit(limit,4,-7))
NextCode: Select all
;Format: LimitF(value,margin1,margin2)
Procedure.f LimitF(number.f,margin1.f,margin2.f)
!fld dword[esp+4] ;push right value to FPU stack
!fld dword[esp+8] ;push left value
!fcomi st1 ;compare st1 (margin2) with st0 (margin1)
!jc near @f ;if st1 (margin2) < st0 (margin1), then:
!fxch ;swap st0 and st1
!@@: ;now we have lower margin at st0, and higher margin at st1
!fld dword[esp] ;push number to FPU stack
!fcomi st1 ;compare number with st1 (the lower margin) for test C flag
!fcmovb st1 ;load st1 into st0 if st1 is greater st0
!jc near @f ;if st0 (number) < st1 (the lower margin), then return the lower margin
!fcomi st2 ;compare number with st2 (the higher margin) for test C flag
!fcmovnb st2 ;load st2 into st0 if st2 is below st0
!@@:
!fstp st1
!fstp st1
EndProcedure
;Prove it:
limitf.f=-5
While limitf<5
Debug StrF(limitf)+" "+StrF(LimitF(limitf,-3.67,-0.45))
limitf+0.3984
WendCode: Select all
;Format: Wrap(value,margin1,margin2)
;NOTE: the range is [lower margin, higher margin] "both inclusive"
Procedure.l Wrap(number.l,margin1.l,margin2.l)
!mov ecx,dword[esp] ;number
!mov eax,dword[esp+4] ;margin1
!mov ebx,dword[esp+8] ;margin2
!cmp eax,ebx ;compare margin values
!jz near Wrapgo ;if margin1 = margin2 then return margin1
!jl near @f ;if margin1 lower than margin2 jump.
!xchg eax,ebx ;swap them
!mov dword[esp+4],eax ;low margin
!mov dword[esp+8],ebx ;right margin
!@@: ;now lower margin is in eax, and higher in ebx
!xor edx,edx ;let edx=0
!sub ebx,eax ;range [lowermargin,highermargin] decremented to floor.
!inc ebx ;to have [lowermargin,highermargin] inclusive
!sub ecx,eax ;number substracted to floor
!mov eax,ecx ;number
!jns near @f ;if number is below lower margin then:
!not eax ;change its sign and decrement it by 1
!div ebx ;modulo is now in edx
!mov eax,dword[esp+8];higher margin
!sub eax,edx ;decrement higher margin by the obtained modulo and return the result
ProcedureReturn
!@@:
!div ebx ;modulo is now in edx
!mov eax,dword[esp+4];lower margin
!add eax,edx ;increment lower margin by the obtained modulo and return the result
!Wrapgo:
ProcedureReturn
EndProcedure
;Prove it:
For t=-40 To 40
Debug Str(t)+" "+Str(Wrap(t,2,-13))
Next
Code: Select all
;Format: WrapF(value.f,margin1.f,margin2.f)
;NOTE: The range is [lowermargin,highermargin) for all values over and under the fringe.
Procedure.f WrapF(number.f,margin1.f,margin2.f)
!fld dword[esp+4] ;push left value to FPU stack (to st1)
!fld dword[esp+8] ;push right value (to st0)
!fcomi st1 ;compares st1 (margin2) with st0 (margin1)
!jz near WrapFEqual ;if margin1 = margin2 then return margin2 (to avoid fprem instruction to divide by 0)
!jnc near @f ;if st0 (margin2) < st1 (margin1), then:
!fxch ;swap st0 and st1, else:
!@@: ;now we have lower margin at st1, and higher margin at st0
!fsub st0,st1 ;range [lowermargin,highermargin] decremented to floor, now in st0
!fld dword[esp] ;push "number" to FPU stack (to st0).
!fsub st0,st2 ;number (st0) substracted to floor. Number now in st0
!;Now "number" in st0. Range in st1. And lower margin in st2
!fprem ;get remainder (modulo) in st0, from the division st0/st1
!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 (is less than lower margin), the modulo is negative too then:
!faddp st1,st0 ;add modulo and range (inverting modulo inside range)
!faddp st1,st0 ;add the result to lower margin
!jmp near WrapFgo
!WrapFEqual:fstp st1
!jmp near WrapFgo
!@@: ;else
!fstp st1 ;don't need anymore the range, so now modulo is in st0
!faddp st1,st0 ;add the modulo to lower margin
!WrapFgo: ;finish returning st0 content
EndProcedure
;Prove it:
t.f=-10
While t<10
Debug StrF(t)+" "+StrF(WrapF(t,5,-2))
t+0.2764564
Wend
Debug "Testing speed... (#msecs. in 1E7 function call)"
DisableDebugger
;Test for speed:
ff.l=gettickcount_()
For tt=1 To 10000000
WrapF(2.453,2.3452,-1.04595)
Next
EnableDebugger
Debug gettickcount_()-ff