Page 1 of 1

Limit(), Wrap()

Posted: Fri Oct 31, 2003 12:08 pm
by Psychophanta
These Limit() and LimitF() are wanted functions when working with plane or spaces, etc.
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))
Next

Code: 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
Wend
These (Wrap() and WrapF()) are to wrap a variable inside a fringe delimited by 2 values:

Code: 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

Re: Limit(), Wrap()

Posted: Fri Oct 31, 2003 7:51 pm
by GPI
About Limit:
Install the UserLibraries-Pack and you can use Range() and RangeF(), which are do exact the same.

GPI

Posted: Fri Oct 31, 2003 8:07 pm
by Kale
Surely:

Code: Select all

if j>800:j=800:endif 
if j<10:j=10:endif
is less code?

Posted: Fri Oct 31, 2003 9:39 pm
by GPI
Kale wrote:Surely:

Code: Select all

if j>800:j=800:endif 
if j<10:j=10:endif
is less code?
j=range(j,10,800)

...

Posted: Fri Oct 31, 2003 9:54 pm
by Andre
@Psychophanta: if Wrap() and Wrap() are used in the same source file, then the variable names (becaused of their different types) can't be the same... [This I could change myself easily :wink:]

But there is another problem: the compiler came up with an "ASM" error, maybe because you used the label 'Go:' in both procedures ?

Posted: Sat Nov 01, 2003 1:26 am
by Psychophanta
The code i added outside functions is only a way to test it. You can put any of your own to test it.

About the go: label:
I have made and test these funcs one by one. Mmmmhh, sorry.
Rather ; I have modified it in the message :wink:

Posted: Sat Nov 01, 2003 5:45 pm
by Andre
Psychophanta wrote:Rather ; I have modified it in the message :wink:
Thanks, so they now can become part of the CodeArchive... :D

Posted: Mon Nov 17, 2003 6:51 pm
by Psychophanta
I've updated Limit(), LimitF(), Wrap() and WrapF().
Before was working, now are "perfect".