Day 003: SGN
#1
A very simple and easy command to understand for day number 3 -- SGN.

What is SGN:  It's simply the command to determine what sign a number has before it.  Is it positive, negative, or 0?

When would we ever use such a command:  Anytime we only need to know whether a value is less than, equal to, or greater than 0.

Example to showcase the command:

Code: (Select All)
For i = -10 To 10
    Print i, Sgn(i)
Next


Honestly, I don't know what more to say about this command as what it does for us is so simple to understand.  Negative numbers return a value of -1.  Positive numbers return a value of +1, and zero, of course, returns a value of 0 as it has no sign.
Reply
#2
My proposed use for SGN is a 3-step process: 1) Wrap it up in a brown paper bag. 2) Place it on the porch of QB64 Official. 3) Light it on fire.

Honestly this is one of the few BASIC keywords that require you to type slightly more code instead of less...

Code: (Select All)
FOR i = -5 TO 5
    PRINT i;
    IF SGN(i) < 0 THEN PRINT "neg", ELSE PRINT "pos",
    IF i < 0 THEN PRINT "neg" ELSE PRINT "pos"
NEXT
PRINT: PRINT SGN(-2 + -6 + 8 + 22 - 33 + -77), -2 + -6 + 8 + 22 - 33 + -77 < 0
PRINT: PRINT SGN(ABS(-2 + -6 + 8 + 22 - 33 + -77)), ABS(-2 + -6 + 8 + 22 - 33 + -77) < 0

Note the only difference is a numerical one, involving the numbers in parentheses. SGN returns -1 for true and 1 for false, where "<" returns zero for false. I really can't see how even that is useful. Special consideration isn't even given to zero. SGN returns zero as positive, so I see no advantage there, either.

Oh well, "Random Generator" is just in its infancy, but I'm pretty sure given the way things are going, it is destined to grow up and be a Magic 8-Ball.

Pete
Reply
#3
Pete, SGN doesn't return true or false but one of 3 values, -1 if x < 0, 1 if x > 0 and 0 if x = 0
Reply
#4
(11-08-2022, 01:39 PM)Pete Wrote: My proposed use for SGN is a 3-step process: 1) Wrap it up in a brown paper bag. 2) Place it on the porch of QB64 Official. 3) Light it on fire.

Honestly this is one of the few BASIC keywords that require you to type slightly more code instead of less...

Code: (Select All)
FOR i = -5 TO 5
    PRINT i;
    IF SGN(i) < 0 THEN PRINT "neg", ELSE PRINT "pos",
    IF i < 0 THEN PRINT "neg" ELSE PRINT "pos"
NEXT
PRINT: PRINT SGN(-2 + -6 + 8 + 22 - 33 + -77), -2 + -6 + 8 + 22 - 33 + -77 < 0
PRINT: PRINT SGN(ABS(-2 + -6 + 8 + 22 - 33 + -77)), ABS(-2 + -6 + 8 + 22 - 33 + -77) < 0

Note the only difference is a numerical one, involving the numbers in parentheses. SGN returns -1 for true and 1 for false, where "<" returns zero for false. I really can't see how even that is useful. Special consideration isn't even given to zero. SGN returns zero as positive, so I see no advantage there, either.

Oh well, "Random Generator" is just in its infancy, but I'm pretty sure given the way things are going, it is destined to grow up and be a Magic 8-Ball.

Pete

Like all commands, @Pete, it's all in how you make use of them.

SGN can be used very quickly to determine direction of objects.

DirectionX = SGN(Position1X - Position2X)

If Position1 is 10, Position2 is 15, 10 - 15 = -5..  You're moving in a negative direction on your screen.
If Position1 is 15, Position2 is 10, 15 - 10 = 5...   You're moving in a positive direction on your screen.
If Position1 = 10, Position2 = 10, 10 - 10 = 0...  You're not moving on your screen.

CAN you do the same thing with IF statements?

SURE -- but it's going to take a lot longer to process.

IF Position1 < Position2 THEN
   direction is positive
ELSEIF Position1 > Position2 THEN
  direction is positive
ELSE
  direction is zero
END IF

Up to 3 comparison checks to do what one simple SGN command can do for you...  Which do you think is going to be faster and keep your program flowing the best?  Particularly when youre dealing with 100 bullets and which direction they're traveling across the screen on your meteoroid clone?



Another quick and easy use -- let's say you're making a ledger to help track your finances.  You want expenditures to be in Red, deposits to be in Black, and zero can just be Gray

DIM Kolors(-1 TO 1) AS _UNSIGNED LONG
Kolors(-1) = Red
Kolors(0) = Gray
Kolors(1) = Black

Then all you need to do when you print onto the screen is a simple:
COLOR Kolors(SGN(number))
PRINT number

No Ifs.  No decisions needing to be made.  Just a quick call to a math function and it's done.
Reply
#5
@Jack

You're right. I didn't check SGN(0) in the code I posted for zero. Oops, my bad. So it does 3 things, but...

Hurry Steve, stomp out that flaming bag of SGN() Big Grin

But wait a sec... Instead of...

Code: (Select All)
Position1X = 10: Position2X = 15
DirectionX = SGN(Position1X - Position2X)
IF DirectionX =-1 THEN PRINT "NEG" ELSE IF DirectionX THEN PRINT "POS" ELSE PRINT "ZERO"

I'd do...

Code: (Select All)
Position1X = 10: Position2X = 15
DirectionX = Position1X - Position2X
IF DirectionX < 0 THEN PRINT "NEG" ELSE IF DirectionX THEN PRINT "POS" ELSE PRINT "ZERO"

A bit less code that way, or a slight bit more to use SELECT CASE for evaluation as:

SELECT CASE. 1, 0 , -1 vs IS > 0 , 0, IS < 0. Not much of a difference.

It is good as a reference point in your code, to see where you need such comparisons on a search. Jut type search SGN.

I vaguely remember using this statement maybe once decades ago but can't recall what for.

Now Steve's second example is a good one, as you'd get bit in the ASCII doing it this way...

COLOR Kolors((number / ABS(number)))

Division by zero is a killer.

So it is good for at least that nice example. Kudos Steve + 1. Now wipe off your shoes before coming back to the forum!

Pete
Reply
#6
Pete
in my math routines I use the same principle to compare 2 numbers, cmp(x, y) would return -1 if x<y, 1 if x>y and 0 if x=y
no need for functions like "is_less", "is_greater" or "is_equal"
Reply
#7
(11-08-2022, 03:13 PM)Pete Wrote: @Jack

You're right. I didn't check SGN(0) in the code I posted for zero. Oops, my bad. So it does 3 things, but...

Hurry Steve, stomp out that flaming bag of SGN() Big Grin

But wait a sec... Instead of...

Code: (Select All)
Position1X = 10: Position2X = 15
DirectionX = SGN(Position1X - Position2X)
IF DirectionX =-1 THEN PRINT "NEG" ELSE IF DirectionX THEN PRINT "POS" ELSE PRINT "ZERO"

I'd do...

Code: (Select All)
Position1X = 10: Position2X = 15
DirectionX = Position1X - Position2X
IF DirectionX < 0 THEN PRINT "NEG" ELSE IF DirectionX THEN PRINT "POS" ELSE PRINT "ZERO"

A bit less code that way, or a slight bit more to use SELECT CASE for evaluation as:

SELECT CASE. 1, 0 , -1 vs IS > 0 , 0, IS < 0. Not much of a difference.

It is good as a reference point in your code, to see where you need such comparisons on a search. Jut type search SGN.

I vaguely remember using this statement maybe once decades ago but can't recall what for.

Now Steve's second example is a good one, as you'd get bit in the ASCII doing it this way...

COLOR Kolors((number / ABS(number)))

Division by zero is a killer.

So it is good for at least that nice example. Kudos Steve + 1. Now wipe off your shoes before coming back to the forum!

Pete

See, @Pete, you're once again doing it wrong. Tongue

If you just wanted to print your direction, then you'd basically just do as I did with Kolors() above -- make an array of strings and then PRINT Direction(DirectionX).  What such routines are generally used for are something more like the following:

Let's say you're making a car chase game.  Your car is chasing the opponents car across the screen.  Instead of a series of IF statements such as you've got drawn out, you'd probably go with something like:

CarX.position = CarX.position + SGN(CarX.position - CarY.position) * SpeedX

Now, CarX is going to change directions if it somehow passes by the other vehicle without crashing into it (they jumped and you went under them, or they hit the transparent boost, or whatever).  No IF is needed, no decisions at work -- just a simple function call to determine SGN which, in this case, determines direction.

SGN isn't useless.  You just need to know when and how to use it properly.  Smile
Reply
#8
Nice. Without it, I'd probably just code:

Code: (Select All)
INPUT CarX.position, CarY.position
speedx = 1
IF CarX.position - CarY.position THEN CarX.position = CarX.position + (CarX.position - CarY.position) / ABS(CarX.position - CarY.position) * speedx
PRINT CarX.position
SLEEP
CLS
RUN
If eggs are brain food, Biden takes his scrambled.
Reply
#9
I disagree with some of you. This is a tool that very few languages other than BASIC thought about implementing. It's because this works with floating-point numbers also. What if you need to check if something is zero? Yeah go ahead and use "ABS()" and subtract, multiply and what have you to make your life more complicated!

From the following code in Freebasic, it displays zero:
Code: (Select All)
dim j as single, z as single
j = 3.3
z = 1.1 + 1.1 + 1.1
j = j - z
print sgn(j)

This should be alike in QB64(PE).
Reply
#10
(11-08-2022, 04:11 PM)Pete Wrote: Nice. Without it, I'd probably just code:

Code: (Select All)
INPUT CarX.position, CarY.position
speedx = 1
IF CarX.position - CarY.position THEN CarX.position = CarX.position + (CarX.position - CarY.position) / ABS(CarX.position - CarY.position) * speedx
PRINT CarX.position
SLEEP
CLS
RUN

Aye, you can always code around notusing it.  Most commands are like that.  Don't like _PRINTSTRING?  Use LOCATE, PRINT, CSRLIN, and POS to duplicate its behavior.

One thing you have to admit though, comparing our two codes -- yours has a lot more to process going on under the hood.  In a game, where FPS matters, that might might a world of difference if inside some inner loop.
Reply




Users browsing this thread: 7 Guest(s)