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

Share your advanced PureBasic knowledge/code with the community.
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

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

Post 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
Last edited by Psychophanta on Tue Mar 21, 2006 10:35 am, edited 3 times in total.
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

Nice! :P Thanx!
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

hey einander, if we keep on feeding psychpanta with snippets with a familiar syntax, we'll end up with puregfa :-)
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post 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:
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post 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...
Seldon
Enthusiast
Enthusiast
Posts: 405
Joined: Fri Aug 22, 2003 7:12 am
Location: Italia

Post 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.
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post 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 :)
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post 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:
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

:lol:
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2137
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Post 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
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post 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)
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Post 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
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post 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:
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

deleted my post, was nonsense
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post 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
Post Reply