Page 1 of 1

Getting the sign of a number

Posted: Sun Oct 02, 2005 12:18 am
by Dr. Dri
Code updated For 5.20+ (As PB supported)

since pb doesn't fully support boolean expressions, i have to write this annoying code :lol:

Code: Select all

Procedure Sgn(x.l)
  ProcedureReturn Bool((x > 0 Or #False) - (x < 0 Or #False))
EndProcedure

Procedure SgnF(x.f)
  ProcedureReturn Bool((x > 0 Or #False) - (x < 0 Or #False))
EndProcedure

Debug Sgn(-5)
Debug Sgn(-0)
Debug Sgn( 5)

Debug SgnF(-5.0)
Debug SgnF(-0.0)
Debug SgnF( 5.0)
Dri :lol:

Posted: Sun Oct 02, 2005 12:53 am
by Xombie
How about...

Code: Select all

Procedure Sgn(a.l)
   ProcedureReturn a >> 31 & 1
EndProcedure

Procedure SgnF(a.f)
   ProcedureReturn Int(a) >> 31 & 1
EndProcedure
Not sure if the SgnF is all that fast because of the Int()

Posted: Sun Oct 02, 2005 12:55 am
by Dr. Dri
doesn't work :?

Code: Select all

Procedure Sgn(a.l)
   ProcedureReturn a >> 31 & 1
EndProcedure

Debug Sgn(-5)
Debug Sgn(-0)
Debug Sgn( 5)
Dri

Posted: Sun Oct 02, 2005 1:04 am
by Xombie
It's always been my understanding that 0 can neither be positive or negative. So zero has no sign. Some math majors want to help me out on this one?

However that fudges my SgnF function for numbers less than one >_>

Posted: Sun Oct 02, 2005 9:00 am
by Psychophanta
But those function are not valid for .b or .w
Here i made one: viewtopic.php?t=8121
But here are 2 different functions for it in which it is improved in size and speed:

Code: Select all

Procedure.b Sgn(n.f)
  !fld dword[esp] ;push FPU stack, and load value to st0
  !fstp st1 ;leaves popped FPU stack while maintaining value in st0
  !ftst   ;test value for update FPU flags.
  !fnstsw ax  ;transfers FPU status word to ax
  !fwait
  !sahf    ;transfers ah to CPU flags.
  !seta al ;if positive al=1, else al=0
  !jnc near @f;if negative jump, else:
  !dec al
  !@@:movsx eax,al ;return and finish
  ProcedureReturn
EndProcedure

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

Posted: Sun Oct 02, 2005 11:03 am
by Dr. Dri
Psychophanta wrote:But those function are not valid for .b or .w
I agree, it's like using a byte or a word with hex(). You need & $FF or $FFFF...

Dri

Posted: Sun Oct 02, 2005 11:17 am
by Psychophanta
Nope, i was wrong!
Your functions works for .b and .w too.

But not needed 2 separate functions; you can resume it in one only function for all PB native types:

Code: Select all

Procedure Sgn(x.f) 
  ProcedureReturn (x > 0 Or #False) - (x < 0 Or #False) 
EndProcedure
However, even it seems to work, that code is not correct for PB specifications :?

Posted: Sun Oct 02, 2005 2:23 pm
by Pupil
If you want something a bit faster, that only works for integers you can use this:

Code: Select all

Procedure Sgn(a.l)
  MOV eax, [esp]
  XOR ebx, ebx
  AND eax, eax
  SETNZ bl
  SAR eax, 31
  OR eax, ebx
  ProcedureReturn
EndProcedure

Posted: Sun Oct 02, 2005 5:05 pm
by Killswitch
0 can't be postive or negative, but 1-0 and 1+0 are equal so it doesn't matter. x^0 = 1, including 0^0=1 - I've always found that weird. Just don't ever divide anything by zero - things get horribly complex then.

Posted: Sun Oct 02, 2005 6:40 pm
by va!n
what about this way?

Code: Select all

Procedure Sgn(x.l)
 If x.l < 0 
  result = #True
 Else
  result = #False
 EndIf
 ProcedureReturn result 
EndProcedure

Procedure SgnF(x.f)
 If x.f < 0 
  result = #True
 Else
  result = #False
 EndIf
 ProcedureReturn result
EndProcedure

Debug Sgn(-5)
Debug Sgn(-0)
Debug Sgn( 5)

Debug SgnF(-5.0)
Debug SgnF(-0.0)
Debug SgnF( 5.0)
Btw, Debug SgnF(-0.0) returns #FALSE, because 0 cant be negative or positive!

Posted: Sun Oct 02, 2005 7:47 pm
by Dr. Dri
@Pupil
Nice example but i'm an ASM begginer so i don't understand :lol:
but it works very well ^^

@va!n
My idea was to return a -1|0|1 which would mean neg|nul|pos

Dri

Posted: Mon Oct 03, 2005 10:16 pm
by MikeB
Psychophanta gave us two routines, as far as I can see the first one works but the second one is wrong for -0.xxxx. Or at least it is wrong for -1/7 which is what I used.

MikeB

Posted: Mon Oct 03, 2005 11:27 pm
by Psychophanta
MikeB wrote:Psychophanta gave us two routines, as far as I can see the first one works but the second one is wrong for -0.xxxx. Or at least it is wrong for -1/7 which is what I used.

MikeB
Oopps!
You're right. Thanx to correct me. I was at the point to add it to my 'tested' collection.
Well, then i gave you only the first one :oops: :)
But here is one much faster, and smaller.
It is tricky, and it has an only problem: if you give it a '-0' value, it will result as '-1'. But apart of that, it works wonderfully:

Code: Select all

Procedure.b Sgn(n.f)
  !mov eax,dword[esp]
  !test eax,eax
  !jz @f
  !sar eax,31
  !bts eax,0
  !@@:
  ProcedureReturn
EndProcedure

Posted: Mon Oct 03, 2005 11:58 pm
by va!n
@Psychophanta
Respect! Very nice! Works fine here! Keep it on! :wink: