Page 1 of 3

Max(), Min(), MaxF(), MinF()

Posted: Thu Oct 30, 2003 10:45 am
by Psychophanta
Code updated For 5.20+

Even i know there are some PB Userlibs which include this i write here this to see what simple and short is to do this in assembler:

Code: Select all

    ;Assembler function to return the lower real value from the given 2.

    ;Author: Psychophanta
    ;Date: 1 Sept 2003

    Procedure.f MinF(n1.f,n2.f)
      !fld dword[p.v_n1]
      !fld dword[p.v_n2]
      !fstp st2
      !fcomi st1
      !fcmovnb st1
      ProcedureReturn
    EndProcedure

    ;prove it:
    Debug MinF(20,178)
    Debug MinF(20.177,20.178)
    Debug MinF(170,20)
    For t=-20 To 20
      Debug MinF(0,t)
    Next
    Debug "******************************************************"
    ;******************************************************
    ;Assembler function to return the higher real value from the given 2.

    ;Author: Psychophanta
    ;Date: 1 Sept 2003

    Procedure.f MaxF(n1.f,n2.f)
      !fld dword[p.v_n1]
      !fld dword[p.v_n2]
      !fstp st2
      !fcomi st1
      !fcmovb st1
      ProcedureReturn
    EndProcedure

    ;prove it:
    Debug MaxF(20,178)
    Debug MaxF(20.177,20.178)
    Debug MaxF(170,20)
    tt.f=-5
    While tt.f<5
      Debug MaxF(tt,-1.00202)
      tt+0.269048
    Wend
    Debug "******************************************************"
    ;******************************************************
    ;Assembler function to return the lower integer value from the given 2.

    ;Author: Psychophanta
    ;Date: 1 Sept 2003

    Procedure Min(n1,n2)
      !mov eax,dword[p.v_n1]
      !cmp eax,dword[p.v_n2]
      !cmovnl eax,dword[p.v_n2] ;for i686 (PentiumPro) and above only
      ProcedureReturn
    EndProcedure

    ;Try it:
    Debug Min(20,178)
    Debug Min(177,178)
    Debug Min(170,20)
    Debug "******************************************************"
    ;******************************************************
    ;Assembler function to return the higher integer value from the given 2.

    ;Author: Psychophanta
    ;Date: 1 Sept 2003

    Procedure Max(n1,n2)
      !mov eax,dword[p.v_n1]
      !cmp eax,dword[p.v_n2]
      !cmovl eax,dword[p.v_n2];<-- NOTE: for i686 (PentiumPro) and above only
      ProcedureReturn
    EndProcedure

    ;Try it:
    Debug Max(20,-178)
    Debug Max(-177,-178)
    Debug Max(170,20)
    Debug "******************************************************"
    ;******************************************************
    Procedure.f MinFMultiple(*base.float,amount);<- no recursive
      result.f=*base\f
      While amount>1
        *base+SizeOf(Float)
        result=MinF(*base\f,result)
        amount-1
      Wend
      ProcedureReturn result
    EndProcedure
    ;
    Procedure.f MinFMultiple0(*base.float,amount);<- recursive
      result.f=*base\f
      If amount>1
        *base+SizeOf(Float)
        result=MinF(MinFMultiple0(*base,amount-1),result)
      EndIf
      ProcedureReturn result
    EndProcedure
    ;******************************************************
    Procedure.f MaxFMultiple(*base.float,amount);<- no recursive
      result.f=*base\f
      While amount>1
        *base+SizeOf(Float)
        result=MaxF(*base\f,result)
        amount-1
      Wend
      ProcedureReturn result
    EndProcedure
    ;
    Procedure.f MaxFMultiple0(*base.float,amount);<- recursive
      result.f=*base\f
      If amount>1
        *base+SizeOf(Float)
        result=MaxF(MaxFMultiple0(*base,amount-1),result)
      EndIf
      ProcedureReturn result
    EndProcedure

Updated to PB 4.0B7

Posted: Thu Oct 30, 2003 11:17 am
by einander
Nice! :P Thanx!

Posted: Thu Oct 30, 2003 11:33 am
by blueznl
hey einander, if we keep on feeding psychpanta with snippets with a familiar syntax, we'll end up with puregfa :-)

Posted: Thu Oct 30, 2003 11:39 am
by Psychophanta
I had an Atari 1040 ST, but i never loved that computer, over all when i knew Amiga.
I knew gfabasic for Atari ST and i loved it a lot.
I knew Amos for Amiga too, but i preferred gfabasic.
But all was better than anything before when i knew BlitzBasic2 for amiga, and i'm sure Fred was inspired on BlitzBasic2 to make PB, i have proofs to demonstrate it :wink:

Posted: Thu Oct 30, 2003 12:13 pm
by einander
blueznl wrote:hey einander, if we keep on feeding psychpanta with snippets with a familiar syntax, we'll end up with puregfa :-)
PureGFA? Great!!! :lol: :lol: :lol:

After 3 months working many hours with PB each day, I'm feeling very comfortable with it
But missing very much GFA auto indexing. That was nice...

Posted: Thu Oct 30, 2003 11:52 pm
by Seldon
But of course ! Fred released the great NewCommandSet for Amiga BlitzBasic: an entire set of optimized and more powerfull commands that did replace most of native BlitzBasic ones. It's nice to see most of the best Windows products came from Amigans: PureBasic, BlitzBasic for Windows (3D and Plus). And I can see many Amigans (or ex) are using them.

Posted: Fri Oct 31, 2003 12:20 pm
by Fred
Psychophanta: 'cmovl' is a 686 instruction only, be careful with it :twisted:

And yes, PureBasic was intended to be the PPC evolution of Blitz2 on Amiga, no wonder why the syntax is so close :)

Posted: Fri Oct 31, 2003 2:51 pm
by Psychophanta
'cmovl' is a 686 instruction only
:oops: I didn't know it, thanks.
PureBasic was intended to be the PPC evolution of Blitz2 on Amiga
Yeah, i knew it :)
By the way, in PB Reference Manual, in LinkedList section, and there in ChangeCurrentElement() function explanation there are an example:

Code: Select all

*Old_Element = @mylist()   ; Get the address of the current element 
  
  ResetList(mylist())        ; Perform a search for all elements named 
  While NextItem(mylist())   ; "John" and change them to "J" 
    If mylist()\name = "John" 
      mylist()\name = "J"     
    EndIf 
  Wend     
  
  ChangeCurrentElement(mylist(), *Old_Element) ; Restore previous current element (from before the search) 
NextItem() :?: :twisted:
That's Blitz2 syntax :wink:

Posted: Fri Oct 31, 2003 4:27 pm
by Fred
:lol:

Posted: Fri Oct 31, 2003 9:35 pm
by Andre
Psychophanta wrote:NextItem() :?: :twisted:
That's Blitz2 syntax :wink:
This part of the manual was written by Tinman, also a good old BB2 expert on Amiga... :lol:
I've corrected it. :D

Posted: Mon Nov 03, 2003 9:48 pm
by Psychophanta
Fred said:
'cmovl' is a 686 instruction only, be careful with it
I sell my Amiga 1200 or perhaps my A500 to whom has a PC with a previous CPU than i686, he/her will give me thanks a lot :lol: 8)

Posted: Sat Nov 08, 2003 6:43 pm
by tinman
Do these procedures work correctly, or have I been drinking too much beer? Try the code below and then try it again after setting the #USE_ASM_PROCEDURES constant to 1. It loosk as if the asm versions result in a calculation error.

Code: Select all

; RGB to HSV colour converter and back again
; From: http://astronomy.swin.edu.au/~pbourke/colour/hsv/

#USE_ASM_PROCEDURES=0

CompilerIf #USE_ASM_PROCEDURES=1
; Uses the MinF and MaxF functions posted to the tricks & tips forum by Psychophanta
Procedure.f MinF(n1.f,n2.f) 
  !fld dword[esp+4] 
  !fld dword[esp] 
  !fcomi st1 
  !fcmovnb st1 
EndProcedure 

Procedure.f MaxF(n1.f,n2.f) 
  !fld dword[esp+4] 
  !fld dword[esp] 
  !fcomi st1 
  !fcmovb st1 
EndProcedure 
CompilerElse

Procedure.f MinF(n1.f, n2.f)
    If n1<n2
        ProcedureReturn n1
    EndIf
    ProcedureReturn n2
EndProcedure

Procedure.f MaxF(n1.f, n2.f)
    If n1>n2
        ProcedureReturn n1
    EndIf
    ProcedureReturn n2
EndProcedure

CompilerEndIf


Structure COLOUR
    r.f
    g.f
    b.f
EndStructure


Structure HSV
    h.f
    s.f
    v.f
EndStructure


;
;    Calculate RGB from HSV, reverse of RGB2HSV()
;    R,G,B are all values between 0 and 1 for intensity of colour
;    Hue is in degrees
;    Lightness is between 0 And 1
;    Saturation is between 0 And 1
Procedure HSV2RGB(*c1.HSV, *rgb.COLOUR)
    DefType.COLOUR  sat

    While *c1\h < 0
        *c1\h = *c1\h + 360
    Wend
   
    While *c1\h > 360
        *c1\h = *c1\h - 360
    Wend

    If *c1\h < 120
        sat\r = (120 - *c1\h) / 60.0
        sat\g = *c1\h / 60.0
        sat\b = 0
    ElseIf *c1\h < 240
        sat\r = 0
        sat\g = (240 - *c1\h) / 60.0
        sat\b = (*c1\h - 120) / 60.0
    Else
        sat\r = (*c1\h - 240) / 60.0
        sat\g = 0
        sat\b = (360 - *c1\h) / 60.0
    EndIf
    
    sat\r = MinF(sat\r, 1)
    sat\g = MinF(sat\g, 1)
    sat\b = MinF(sat\b, 1)

    *rgb\r = (1 - *c1\s + *c1\s * sat\r) * *c1\v
    *rgb\g = (1 - *c1\s + *c1\s * sat\g) * *c1\v
    *rgb\b = (1 - *c1\s + *c1\s * sat\b) * *c1\v
EndProcedure


;
;    Calculate HSV from RGB
;    R,G,B are all values between 0 and 1 for intensity of colour
;    Hue is in degrees
;    Lightness is betweeen 0 And 1
;    Saturation is between 0 And 1
Procedure RGB2HSV(*c1.COLOUR, *hsv.HSV)
    DefType.f   themin,themax,delta

    themin = MinF(*c1\r,MinF(*c1\g,*c1\b))
    themax = MaxF(*c1\r,MaxF(*c1\g,*c1\b))
    delta = themax - themin
    
    Debug themax
    Debug themin
    Debug delta
    
    *hsv\v = themax
    *hsv\s = 0
    If themax > 0
        *hsv\s = delta / themax
    EndIf
    
    *hsv\h = 0
    If delta > 0
        If themax=*c1\r And themax<>*c1\g
            *hsv\h = *hsv\h + ((*c1\g - *c1\b) / delta)
        EndIf
       
        If themax=*c1\g And themax<>*c1\b
            *hsv\h = *hsv\h + (2 + (*c1\b - *c1\r) / delta)
        EndIf
        
        If themax=*c1\b And themax<>*c1\r
            *hsv\h = *hsv\h + (4 + (*c1\r - *c1\g) / delta)
        EndIf
        
        *hsv\h = *hsv\h * 60
    EndIf
EndProcedure


; Small demo
DefType.COLOUR  rgb
DefType.HSV     hsv

rgb\r = 1 : rgb\g = 0 : rgb\b = 0
RGB2HSV(@rgb, @hsv)
Debug StrF(hsv\h)+", "+StrF(hsv\s)+", "+StrF(hsv\v)

;hsv\h = 0 : hsv\s = 1 : hsv\v = 1
HSV2RGB(@hsv, @rgb)
Debug StrF(rgb\r)+", "+StrF(rgb\g)+", "+StrF(rgb\b)

End

Posted: Sat Nov 08, 2003 8:55 pm
by Psychophanta
Just put "!finit" as the first instruction of both procedures.

:oops:
It was made quickly, to demonstrate myself and others that ASM is not so difficult to do some little things. :wink:

Posted: Mon Nov 10, 2003 4:50 pm
by blueznl
deleted my post, was nonsense

Posted: Mon Nov 17, 2003 6:45 pm
by Psychophanta
I have updated Min(), MinF(), Max() and MaxF() function.
Before was just working, now are "perfect".

I take advantage to add Sgn() here, for floats and integers:

Code: Select all

Procedure.b Sgn(n.f)
  !fld dword[esp] ;push FPU stack, and load value to st0
  !fstp st1 ;left popped FPU stack while maintaining value in st0
  !ftst   ;test value for update FPU flags.
  !fnstsw ax  ;transfers FPU status word to ax
  !fwait
  !xor al,al;let al=0
  !sahf    ;transfers ah to CPU flags.
  !jz near @f;if 0, that's all.
  !inc al;else al=1
  !;inc instruction doesn't modify CPU C flag ;)
  !jnc near @f;if positive, that's all
  !neg al;else al=-1
  !@@:movsx eax,al ;return and finish
  ProcedureReturn
EndProcedure

;Prove it:
r.f=7
Debug Sgn(4.786594)
Debug Sgn(-v.b)
Debug Sgn(-r.f)
Debug ""
For t.w=-20 To 20
  Debug Sgn(t.w)
Next